groupWebRTCCallCtr.vue 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  1. <template>
  2. <page-meta :page-font-size="fontValue+'px'" :root-font-size="fontValue+'px'"></page-meta>
  3. <view>
  4. <cu-custom :isBack='true' >
  5. <template v-slot:content>
  6. <text class="text-jiachu text-black">群组通话</text>
  7. </template>
  8. </cu-custom>
  9. <view class="IncolumnC">
  10. <image class="AvatarImg" :src="friendAvatar" mode="scaleToFill"></image>
  11. <text v-if="friend.value" class="text-black text-lg"></text>
  12. <text class="text-black text-lg" style="margin-top: 10rpx;">{{friendName}}</text>
  13. <view class="InrowC" style="margin-top: 80rpx;">
  14. <text class="text-black text-lg">{{stateNote}}</text>
  15. <image style="width: 52rpx;height: 52rpx;margin-left: 6rpx;" src="/static/mine/loading2.gif" mode=""></image>
  16. </view>
  17. <view class="InrowC" style="margin-top: 300rpx;">
  18. <image v-if="!canClose" style="width:110rpx ;height: 110rpx;" src="/static/mine/icon_on.png" mode="scaleToFill" @click="acceptWebrtc"></image>
  19. <image v-if="canClose" style="width:110rpx ;height: 110rpx;" src="/static/mine/icon_off.png" mode="scaleToFill" @click="closeWebrtcBT"></image>
  20. <image v-if="speacker" style="margin-left: 50rpx;width:110rpx ;height: 110rpx;" src="/static/mine/ysq_on.png" mode="scaleToFill" @click="changeSpeack"></image>
  21. <image v-if="!speacker" style="margin-left: 50rpx;width:110rpx ;height: 110rpx;" src="/static/mine/ysq_off.png" mode="scaleToFill" @click="changeSpeack"></image>
  22. </view>
  23. </view>
  24. </view>
  25. </template>
  26. <script setup lang="ts">
  27. import {onLoad,onReady,onShow,onUnload} from '@dcloudio/uni-app';
  28. import {ref,watch} from 'vue'
  29. import * as ASCIIUtils from '@/uni_modules/wrs-js-modbusCRCHex/js_sdk/wrs-ASCIIUtils.js';
  30. import * as HexUtils from '@/uni_modules/wrs-js-modbusCRCHex/js_sdk/wrs-HexUtils.js';
  31. import {
  32. UTSWebRTC
  33. } from "@/uni_modules/wrs-uts-webrtc";
  34. import {
  35. UTSVoipMgr
  36. } from "@/uni_modules/wrs-uts-voip"
  37. import MessageUtils from "@/utils/MessageUtils";
  38. import CuCustom from '@/colorui/components/cu-custom.vue'
  39. import UserApi from "@/api/UserApi";
  40. import {useUserStore} from '@/store/userStore'
  41. import {useWsStore} from "@/store/WsStore";
  42. import {storeToRefs} from "pinia";
  43. import type Webrtc from '@/mode/Webrtc';
  44. import ChatType from "@/utils/ChatType";
  45. import {usePeerStore} from "@/store/peerStore";
  46. import SendCode from '@/utils/SendCode'
  47. import Auth from "@/api/Auth";
  48. const fontValue=ref(Auth.getfontSize());
  49. let webRTC = new UTSWebRTC();
  50. let candidateList=[];
  51. let usersId = [];
  52. let otherPersons=[];
  53. let friendAvatar='/static/logo512.png';
  54. let friendName='';
  55. let stateNote =ref("正在呼叫");
  56. let audioObj=null;
  57. const timeCall=ref(0);
  58. const timer=ref();
  59. const wsStore = useWsStore();
  60. const peerStore = usePeerStore();
  61. const friendId = ref("");
  62. const friend = ref("");
  63. const startTime = ref(0)
  64. const isCaller = ref(false);
  65. const showVideo = ref(false);
  66. const speacker = ref(false);
  67. const canClose = ref(true);
  68. const user = useUserStore().getUser()
  69. const isConnect = ref(false)
  70. const videoIsOpen = ref(false)
  71. const hadClose = ref(false);
  72. const androidpermission = ref(false);
  73. const {isClose} = storeToRefs(peerStore)
  74. const {offer} = storeToRefs(peerStore)
  75. const {answer} = storeToRefs(peerStore)
  76. const {candidate} = storeToRefs(peerStore)
  77. const {isAccept} = storeToRefs(peerStore)
  78. watch(isAccept, (newVal) => {
  79. if (newVal) {
  80. timeCall.value=45;
  81. startTime.value = new Date().getTime()
  82. createPeerConnection(friendId.value);
  83. getoffer();
  84. }
  85. })
  86. watch(isClose, (newVal) => {
  87. console.log('isCloseisClose',newVal)
  88. if (newVal) {
  89. if(videoIsOpen.value){
  90. //通知视频播放页面关闭
  91. let data={
  92. type:'isClose'
  93. }
  94. uni.$emit('webRTCvideoE', { msg:JSON.stringify(data)});
  95. }
  96. else{
  97. uni.navigateBack()
  98. }
  99. }
  100. })
  101. watch(offer, (newVal) => {
  102. if (newVal) {//收到offer
  103. recOffer(newVal);
  104. }
  105. })
  106. watch(answer, (newVal) => {
  107. if (newVal) {//收到answer
  108. recAnswer(newVal);
  109. }
  110. })
  111. watch(candidate, (newVal) => {
  112. if (newVal) {//收到candidate
  113. console.log('candidate--------');
  114. recCandidate(newVal);
  115. }
  116. })
  117. const chaoshipanduan = () => {
  118. timeCall.value=45;
  119. timer.value = setInterval(() => {
  120. timeCall.value=timeCall.value-1;
  121. if(timeCall.value==0&&!isConnect.value){
  122. MessageUtils.message('暂时无法连接,请稍后重试!')
  123. }
  124. else if(isConnect.value){
  125. clearInterval(timer.value);//正常接通
  126. return;
  127. }
  128. else if(timeCall.value<-2&&!isConnect.value){
  129. uni.navigateBack();
  130. }
  131. }, 1000);
  132. }
  133. const audioObjstart = () => {
  134. audioObj=uni.createInnerAudioContext();
  135. audioObj.loop=true;
  136. audioObj.volume=0.2;
  137. audioObj.src='/hybrid/html/images/calling.mp3';
  138. audioObj.play();
  139. }
  140. const audioObjstop = () => {
  141. if(audioObj){
  142. audioObj.stop();
  143. }
  144. }
  145. onShow(()=>{
  146. // console.log('onShow',videoIsOpen.value)
  147. if(videoIsOpen.value){
  148. uni.navigateBack();
  149. return;
  150. }
  151. if(uni.getSystemInfoSync().platform == "ios"){
  152. let state = UTSVoipMgr.getApplicationState();
  153. if(state!=2){
  154. if(!isCaller.value){
  155. //let provider = new UTSCXProvider()
  156. UTSVoipMgr.endCall({
  157. uuid: uni.getStorageSync("voip_UUID")
  158. }, (resp: any)=>{
  159. console.log(JSON.stringify(resp))
  160. })
  161. }
  162. initData();
  163. //getfriendMsg();
  164. //audioObjstart();
  165. setTimeout(function() {
  166. // 这里写要延时执行
  167. if(isCaller.value){//主动发起通话
  168. }
  169. else{
  170. //acceptWebrtc();//自动接听
  171. receiveJoin(friendId.value);
  172. }
  173. }, 1500);
  174. }
  175. }
  176. else{
  177. initData();
  178. //getfriendMsg();
  179. setTimeout(function() {
  180. // 这里写要延时执行
  181. if(isCaller.value){//主动发起通话
  182. }
  183. else{
  184. receiveJoin(friendId.value);
  185. //acceptWebrtc();//自动接听
  186. }
  187. }, 1500);
  188. }
  189. // console.log('getApplicationstate2-------',state);
  190. })
  191. onReady(()=>{
  192. console.log('onReady');
  193. chaoshipanduan();
  194. setTimeout(function() {
  195. // 这里写要延时执行的代码
  196. if(showVideo.value){
  197. console.log('onReady1');
  198. webRTC.setSpeakerEnable(true)
  199. speacker.value=true;
  200. }
  201. else{
  202. console.log('onReady2');
  203. webRTC.setSpeakerEnable(false)
  204. }
  205. }, 300);
  206. });
  207. onLoad((opt) => {
  208. console.log(opt)
  209. usePeerStore().updateBusyStatus(true)
  210. usePeerStore().updateCloseStatus(false)
  211. if(typeof opt?.showVideo === 'string'){
  212. showVideo.value = opt?.showVideo === 'true'
  213. }
  214. candidateList=[];
  215. friendId.value = opt?.friendId;
  216. if(typeof opt?.isCaller === 'string'){
  217. isCaller.value = opt?.isCaller === 'true'
  218. if(isCaller.value){
  219. canClose.value = true;
  220. console.log('onLoad',usePeerStore().users);
  221. usersId=JSON.parse(usePeerStore().users);
  222. joinRoom();
  223. }
  224. console.log('isCaller',canClose);
  225. }
  226. audioObjstart();
  227. // 开始本地抓流
  228. if (uni.getSystemInfoSync().platform == "ios") {
  229. }
  230. else{
  231. requestPermission([
  232. "android.permission.CAMERA",
  233. "android.permission.RECORD_AUDIO"
  234. ])
  235. }
  236. });
  237. onUnload(()=>{
  238. clearInterval(timer.value);//正常接通
  239. audioObjstop();
  240. if(!hadClose.value){
  241. closeWebrtc();
  242. }
  243. webRTC.destroyAllPeerConnection();
  244. peerStore.setCallId(undefined);
  245. peerStore.setOffer(undefined);
  246. peerStore.setAnswer(undefined);
  247. peerStore.setCandidate(undefined);
  248. peerStore.updateBusyStatus(false);
  249. peerStore.updateCloseStatus(false);
  250. peerStore.setIsAccept(false);
  251. });
  252. const requestPermission = (permissions:any) =>{
  253. plus.android.requestPermissions(
  254. permissions,
  255. function(resultObj) {
  256. for (var i = 0; i < resultObj.granted.length; i++) {
  257. var grantedPermission = resultObj.granted[i];
  258. androidpermission.value=true;
  259. console.log('已获取的权限:' + grantedPermission);
  260. if(grantedPermission=='android.permission.CAMERA'){
  261. webRTC.startVideoCapture({
  262. isFront:true,
  263. width: 1280,
  264. height: 720,
  265. fps: 30
  266. })
  267. }
  268. }
  269. for (var i = 0; i < resultObj.deniedPresent.length; i++) {
  270. var deniedPresentPermission = resultObj.deniedPresent[i];
  271. console.log('拒绝本次申请的权限:' + deniedPresentPermission);
  272. }
  273. for (var i = 0; i < resultObj.deniedAlways.length; i++) {
  274. var deniedAlwaysPermission = resultObj.deniedAlways[i];
  275. console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);
  276. }
  277. // 若所需权限被永久拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限
  278. if (resultObj.deniedAlways.length > 0) {
  279. // var Intent = plus.android.importClass("android.content.Intent");
  280. // var Settings = plus.android.importClass("android.provider.Settings");
  281. // var Uri = plus.android.importClass("android.net.Uri");
  282. // var mainActivity = plus.android.runtimeMainActivity();
  283. // var intent = new Intent();
  284. // intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
  285. // var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);
  286. // intent.setData(uri);
  287. // mainActivity.startActivity(intent);
  288. }
  289. },
  290. function(error) {
  291. console.log('申请权限错误:' + error.code + " = " + error.message);
  292. });
  293. }
  294. const initData = () =>{
  295. console.log('initWebRTC')
  296. // 设置webRTC的回调
  297. webRTC.onCallback((resp:any) => {
  298. let opt = resp.opt
  299. console.log("webRTC.onCallback opt:" + opt)
  300. switch (opt) {
  301. // 信令状态改变
  302. case "onSignalingChange": {
  303. console.log("onSignalingChange:" + JSON.stringify(resp))
  304. let state = resp.state
  305. if (state) {
  306. switch (state) {
  307. case 0: {
  308. console.log("RTCSignalingStateStable")
  309. }
  310. break;
  311. case 1: {
  312. console.log("RTCSignalingStateHaveLocalOffer")
  313. }
  314. break;
  315. case 2: {
  316. console.log("RTCSignalingStateHaveLocalPrAnswer")
  317. }
  318. break;
  319. case 3: {
  320. //
  321. console.log("RTCSignalingStateHaveRemoteOffer")
  322. }
  323. break;
  324. case 4: {
  325. console.log("RTCSignalingStateHaveRemotePrAnswer")
  326. }
  327. break;
  328. case 5: {
  329. console.log("RTCSignalingStateClosed")
  330. let userId = resp.userId
  331. if (userId) {
  332. //this.userLeave(userId)
  333. }
  334. }
  335. break;
  336. default:
  337. break;
  338. }
  339. }
  340. }
  341. break;
  342. case "onIceGatheringChange": {
  343. console.log("onIceGatheringChange:" + JSON.stringify(resp))
  344. let state = resp.state
  345. if (state) {
  346. switch (state) {
  347. case 0: {
  348. console.log("RTCIceGatheringStateNew")
  349. }
  350. break;
  351. case 1: {
  352. console.log("RTCIceGatheringStateGathering")
  353. }
  354. break;
  355. case 2: {
  356. console.log("RTCIceGatheringStateComplete")
  357. }
  358. break;
  359. default:
  360. break;
  361. }
  362. }
  363. }
  364. break;
  365. // 生成IceCandidate
  366. case "onIceCandidate": {
  367. let userId = resp.userId
  368. console.log("onIceCandidate--",userId)
  369. let candidate = resp.iceCandidate
  370. let data = {
  371. candidate: candidate.sdp,
  372. sdpMLineIndex: candidate.sdpMLineIndex,
  373. sdpMid: candidate.sdpMid,
  374. }
  375. let tempList = [];
  376. tempList.push(data);
  377. sendCandidate(tempList);
  378. }
  379. break;
  380. case "onIceConnectionChange": {
  381. console.log("onIceConnectionChange:" + JSON.stringify(resp))
  382. let state = resp.state
  383. switch (state) {
  384. case 0: {
  385. console.log("RTCIceConnectionStateNew")
  386. }
  387. break;
  388. case 1: {
  389. console.log("RTCIceConnectionStateChecking")
  390. }
  391. break;
  392. case 2: {
  393. // 这步没有
  394. console.log("RTCIceConnectionStateConnected");
  395. stateNote.value ='已连接';
  396. isConnect.value=true;
  397. audioObjstop();
  398. console.log('------1',showVideo.value,videoIsOpen.value)
  399. if(showVideo.value&&!videoIsOpen.value){//打开视频
  400. videoIsOpen.value=true;
  401. webRTC.setSpeakerEnable(true)
  402. console.log('------2',showVideo.value,videoIsOpen.value)
  403. uni.navigateTo({
  404. url:'/imcall/webRTCVideoView'
  405. })
  406. setTimeout(function() {
  407. // 这里写要延时执行的代码
  408. let data={
  409. type:'users',
  410. users:otherPersons
  411. }
  412. uni.$emit('webRTCvideoE', { msg:JSON.stringify(data)});
  413. }, 1000);
  414. }
  415. }
  416. break;
  417. case 3: {
  418. console.log("RTCIceConnectionStateCompleted")
  419. }
  420. break;
  421. case 4: {
  422. console.log("RTCIceConnectionStateFailed")
  423. stateNote.value ='连接已断开';
  424. }
  425. break;
  426. case 5: {
  427. // 通讯被断开,一般是对方掉线或者STUN/TURN 服务器问题:如果 ICE 服务器配置不当,或者 STUN/TURN 服务器不可用,可能会导致连接失败。确保你的 STUN/TURN 服务器正常工作并且可达。
  428. stateNote.value ='连接已断开';
  429. console.log("RTCIceConnectionStateDisconnected")
  430. let data={
  431. type:'state',
  432. stateNote:stateNote.value
  433. }
  434. uni.$emit('webRTCvideoE', { msg:JSON.stringify(data)});
  435. let userId = resp.userId
  436. if (userId) {
  437. //this.userLeave(userId)
  438. }
  439. }
  440. break;
  441. case 6: {
  442. console.log(" RTCIceConnectionStateClosed")
  443. stateNote.value ='连接已断开';
  444. let userId = resp.userId
  445. if (userId) {
  446. //this.userLeave(userId)
  447. }
  448. }
  449. break;
  450. case 7: {
  451. console.log(" RTCIceConnectionStateCount")
  452. }
  453. break;
  454. default:
  455. break;
  456. }
  457. }
  458. break;
  459. // 收到其他用户的音频或视频流
  460. case "onAddStream": {
  461. let userId = resp.userId
  462. console.log("onAddStream:",resp)
  463. if (userId) {
  464. let stream = resp.stream
  465. if (stream) {
  466. // 如果有视频流,则显示其他用户的视频
  467. let videoTracks = stream.videoTracks
  468. if (videoTracks) {
  469. if (videoTracks.length > 0) {
  470. let users=[];
  471. users.push(friendId.value);
  472. let exist =existUser(userId)
  473. if (!exist) {
  474. console.log("显示远程视频流:" + userId)
  475. otherPersons.push({
  476. userId: userId
  477. })
  478. let data={
  479. type:'users',
  480. users:otherPersons
  481. }
  482. uni.$emit('webRTCvideoE', { msg:JSON.stringify(data)});
  483. }
  484. }
  485. }
  486. }
  487. }
  488. }
  489. break;
  490. case "onRemoveStream": {
  491. }
  492. break;
  493. default:
  494. break;
  495. }
  496. })
  497. console.log('initWebRTC11')
  498. // 初始化视频
  499. webRTC.initVideoTrack({
  500. trackId: "video0",
  501. isScreencast: false // 仅对Android生效
  502. })
  503. // 初始化音频
  504. webRTC.initAudioTrack({
  505. trackId: "audio0"
  506. })
  507. console.log('initWebRTC22')
  508. if (uni.getSystemInfoSync().platform == "ios") {
  509. webRTC.configureAudioSession({
  510. category: "playAndRecord",
  511. mode: "voiceChat"
  512. })
  513. } else {
  514. }
  515. // 开始本地抓流
  516. if (uni.getSystemInfoSync().platform == "ios") {
  517. webRTC.startVideoCapture({
  518. isFront:true,
  519. width: 1280,
  520. height: 720,
  521. fps: 30
  522. })
  523. }
  524. };
  525. const getfriendMsg = () => {
  526. UserApi.getUser(friendId.value).then((res) => {
  527. friend.value = res.data
  528. if (friend.value) {
  529. friendName=friend.value.name;
  530. friendAvatar=encodeURI(friend.value.avatar);
  531. if(isCaller.value){//主动发起通话
  532. //sendcallingMsg();
  533. }
  534. else{
  535. //acceptWebrtc();//自动接听
  536. }
  537. }
  538. })
  539. }
  540. const changeSpeack = () => {
  541. if(speacker.value){
  542. speacker.value=false;
  543. }
  544. else{
  545. speacker.value=true;
  546. }
  547. console.log('setAudioEnabled',speacker.value)
  548. webRTC.setSpeakerEnable(speacker.value)
  549. }
  550. const acceptWebrtc = () => {
  551. console.log('acceptWebrtc');
  552. //给自己发一份忙碌状态,多个客户端同一个人不能同时接受,需要客户端接受后,其他客户端就关闭
  553. let data={
  554. code: SendCode.WEBRTC_BUSY,
  555. message: {
  556. chatId:friendId.value,
  557. fromId: user.id,
  558. type: ChatType.FRIEND,
  559. msgtype:'accept',
  560. video: showVideo.value,
  561. }
  562. }
  563. console.log(data);
  564. useWsStore().send(JSON.stringify(data));
  565. canClose.value = true;
  566. }
  567. const closeWebrtcBT = () => {
  568. uni.navigateBack();
  569. }
  570. const closeWebrtc = () => {
  571. if (user.id) {
  572. const closeMessage = {
  573. code: SendCode.WEBRTC_CLOSE,
  574. message: {
  575. chatId:friendId.value,
  576. fromId: user.id,
  577. timestamp: new Date().getTime(),
  578. type: ChatType.FRIEND,
  579. msgtype:'close'
  580. }
  581. }
  582. wsStore.send(JSON.stringify(closeMessage))
  583. hadClose.value=true;
  584. console.log('发送关闭消息', closeMessage)
  585. //发起方才有发送视频结果消息的权限
  586. if (isCaller.value) {
  587. //界面展示视频消息情况,例如:对方是否接受了视频通话,通话时长
  588. const message= {
  589. id:null,
  590. localtime:null,
  591. mine:true,
  592. messageType:SendCode.WEBRTC_result,
  593. chatId:friendId.value,
  594. fromId: user.id,
  595. timestamp: new Date().getTime(),
  596. type: ChatType.FRIEND,
  597. result: isConnect.value,
  598. video: showVideo.value,
  599. duration: isConnect.value ? new Date().getTime() - startTime.value : 0
  600. }
  601. console.log(message)
  602. wsStore.sendWEBRTCresult(message);
  603. }
  604. }
  605. }
  606. const sendSocketData = (data:any) => {
  607. wsStore.sendWEBRTC(data)
  608. console.log('发送消息', data);
  609. }
  610. const sendCandidate = (candidateList:any) =>{
  611. let msg: Webrtc = {
  612. chatId: friendId.value,
  613. fromId: user.id,
  614. type: ChatType.FRIEND,
  615. msgtype:'candidate',
  616. conetType:showVideo.value,
  617. payload:JSON.stringify(candidateList)
  618. }
  619. console.log("将本机candidate发送给对方")
  620. sendSocketData(msg);
  621. }
  622. //主动发起通话操作,isCaller为true-----------------------------
  623. const sendcallingMsg = (othfriendId:any) => {
  624. console.log('sendcallingMsg');
  625. let msg: Webrtc = {
  626. chatId:othfriendId,
  627. fromId: user.id,
  628. type: ChatType.GROUP,
  629. msgtype:'calling',
  630. conetType:showVideo.value,
  631. timestamp: new Date().getTime(),
  632. payload:''
  633. }
  634. let data={
  635. code:SendCode.WEBRTC_CALL,
  636. message: msg
  637. }
  638. console.log('sendcallingMsg',data);
  639. useWsStore().send(JSON.stringify(data))
  640. }
  641. // 创建与某个用户的连接
  642. const createPeerConnection = (userId:any) => {
  643. let hasPeerConnection = webRTC.hasPeerConnection({
  644. userId: userId
  645. })
  646. if (!hasPeerConnection) { // 如果没有连接则创建连接
  647. console.log("当前用户没有连接,正在创建")
  648. let params = {
  649. iceServers:[],
  650. sdpSemantics:1,
  651. continualGatheringPolicy:1,
  652. constraints:{},
  653. userId:''
  654. }
  655. params.iceServers = [{
  656. urls: ["stun:203.175.169.52:3478",
  657. "turn:203.175.169.52:3478"
  658. ],
  659. username: 'aaaaa',
  660. credential: 'bbbbb'
  661. }
  662. ]
  663. params.userId = userId;
  664. params.sdpSemantics = 1 // 0: RTCSdpSemanticsPlanB 1:RTCSdpSemanticsUnifiedPlan
  665. params.continualGatheringPolicy =
  666. 1 // 0: RTCContinualGatheringPolicyGatherOnce 1: RTCContinualGatheringPolicyGatherContinually
  667. params.constraints = {
  668. mandatory: {},
  669. optional: {
  670. DtlsSrtpKeyAgreement: "true"
  671. }
  672. }
  673. userId = webRTC.createPeerConnection(params)
  674. // 给连接添加本地视频
  675. console.log("添加本地视频")
  676. let videoResp = webRTC.addVideoTrack({
  677. userId: userId,
  678. streamIds: ["video0"]
  679. })
  680. let videoFlag = videoResp.flag
  681. if (!videoFlag) {
  682. console.log("添加本地视频出错:" + JSON.stringify(videoFlag))
  683. }
  684. // 给连接添加本地音频
  685. console.log("添加本地音频")
  686. let audioResp = webRTC.addAudioTrack({
  687. userId: userId,
  688. streamIds: ["audio0"]
  689. })
  690. let audioFlag = audioResp.flag
  691. if (!audioFlag) {
  692. console.log("添加本地音频出错:" + JSON.stringify(videoFlag))
  693. }
  694. } else {
  695. console.log("已经有连接,无需创建")
  696. }
  697. };
  698. const getoffer = () => {
  699. // var videoV="false";
  700. // if(showVideo.value){
  701. // videoV="true";
  702. // }
  703. console.log('getoffer')
  704. webRTC.createOffer({
  705. userId:friendId.value,
  706. setLocalDescription: false
  707. }, (resp:any) => {
  708. console.log(resp);
  709. let flag = resp.flag
  710. if (flag) {
  711. let sessionDescription = resp.sessionDescription
  712. let type = sessionDescription.type
  713. let sdp = sessionDescription.sdp
  714. console.log('sessionDescription',sessionDescription)
  715. webRTC.setLocalDescription({
  716. userId: friendId.value,
  717. type: type,
  718. sdp: sdp
  719. }, (localDescResp:any) => {
  720. let localFlag = localDescResp.flag
  721. console.log('setLocalDescription',localFlag)
  722. })
  723. let data = {
  724. type: "SessionDescription",
  725. payload: {
  726. sdp:sdp,
  727. type: type
  728. }
  729. }
  730. let msg: Webrtc = {
  731. chatId: friendId.value,
  732. fromId: user.id,
  733. type: ChatType.FRIEND,
  734. msgtype:'offer',
  735. conetType:showVideo.value,
  736. payload:JSON.stringify(data.payload)
  737. }
  738. // 发送给接听方
  739. sendSocketData(msg)
  740. }
  741. }
  742. )
  743. }
  744. //收到answer
  745. const recAnswer = (strdata:string) => {
  746. let data=JSON.parse(strdata);
  747. console.log("recOffer:--",data)
  748. if(data.msgtype!='answer'){
  749. return;
  750. }
  751. let answer=JSON.parse(data.payload)
  752. console.log('answeroffer1----',answer);
  753. createPeerConnection(data.fromId)
  754. webRTC.setRemoteDescription({
  755. userId:data.fromId,
  756. type: "answer",
  757. sdp: answer.sdp
  758. }, (resp:any) => {
  759. let flag = resp.flag
  760. console.log('answeroffer2----',resp);
  761. })
  762. }
  763. //被动接听通话操作,isCaller为false-----------------------------
  764. //收到recOffer
  765. const recOffer = (strdata:string) => {
  766. let data=JSON.parse(strdata);
  767. console.log("recOffer:--",data)
  768. if(data.msgtype!='offer'){
  769. return;
  770. }
  771. createPeerConnection(data.fromId)
  772. // 设置远程Description
  773. let payload=JSON.parse(data.payload);
  774. webRTC.setRemoteDescription({
  775. userId:data.fromId,
  776. type: payload.type,
  777. sdp: payload.sdp
  778. }, (resp) => {
  779. let flag = resp.flag
  780. if (flag) {
  781. console.log("生成answer")
  782. // 生成answer
  783. webRTC.createAnswer({
  784. userId:data.fromId,
  785. setLocalDescription: false
  786. }, (answerResp:any) => {
  787. let flag = answerResp.flag
  788. if (flag) {
  789. // console.log("createAnswer result:" + JSON.stringify())
  790. let sessionDescription = answerResp.sessionDescription
  791. let type = sessionDescription.type
  792. let sdp = sessionDescription.sdp
  793. // 设置本地Description
  794. console.log("设置setLocalDescription")
  795. webRTC.setLocalDescription({
  796. userId:data.fromId,
  797. type: type,
  798. sdp: sdp
  799. }, (localDescResp:any) => {
  800. let localFlag = localDescResp.flag
  801. if (localFlag) {
  802. // 发送answer
  803. let msg: Webrtc = {
  804. chatId:data.fromId,
  805. fromId:user.id,
  806. type: ChatType.FRIEND,
  807. msgtype:'answer',
  808. conetType:showVideo.value,
  809. payload:JSON.stringify({sdp:sdp,type: type})
  810. }
  811. console.log('answer',msg)
  812. sendSocketData(msg)
  813. } else {
  814. console.log("setLocalDescription error:" + JSON
  815. .stringify(
  816. localDescResp))
  817. }
  818. })
  819. } else {
  820. console.log("createAnswer error:" + JSON.stringify(resp))
  821. }
  822. })
  823. } else {
  824. console.log("setRemoteDescription error:")
  825. }
  826. })
  827. }
  828. const recCandidate = (strdata:any) => {
  829. let data = JSON.parse(strdata);
  830. console.log(data);
  831. if(data.msgtype!='candidate'){
  832. return;
  833. }
  834. let hasPeerConnection = webRTC.hasPeerConnection({userId: data.fromId})
  835. if (!hasPeerConnection) {
  836. return
  837. }
  838. let datalist = JSON.parse(data.payload)
  839. datalist.forEach((item) => {
  840. console.log("添加远程IceCandidate:" + JSON.stringify(item))
  841. // 添加远程IceCandidate
  842. webRTC.addIceCandidate({
  843. userId:data.fromId,
  844. sdpMid:item.sdpMid,
  845. sdpMLineIndex: item.sdpMLineIndex,
  846. sdp: item.candidate
  847. }, (resp:any) => {
  848. let flag = resp.flag
  849. if (!flag) {
  850. console.log("addIceCandidate error:" + JSON.stringify(resp))
  851. }
  852. })
  853. })
  854. }
  855. // const answer = () => {
  856. // var videoV="false";
  857. // if(showVideo.value){
  858. // videoV="true";
  859. // }
  860. // webRTC.answer({
  861. // OfferToReceiveAudio: "true",
  862. // OfferToReceiveVideo:videoV
  863. // }, (resp) => {
  864. // let flag = resp.flag
  865. // if (flag) {
  866. // let sdp = resp.sdp
  867. // let type = ""
  868. // switch (sdp.type) {
  869. // case 0:
  870. // type = "offer"
  871. // break;
  872. // case 1:
  873. // type = "prAnswer"
  874. // break;
  875. // case 2:
  876. // type = "answer"
  877. // break;
  878. // case 3:
  879. // type = "rollback"
  880. // break;
  881. // default:
  882. // break;
  883. // }
  884. // let data = {
  885. // type: "SessionDescription",
  886. // payload: {
  887. // sdp: sdp.sdp,
  888. // type: type
  889. // }
  890. // }
  891. // // 发送给呼叫方
  892. // let msg: Webrtc = {
  893. // chatId:friendId.value,
  894. // fromId:user.id,
  895. // type: ChatType.FRIEND,
  896. // msgtype:'answer',
  897. // conetType:showVideo.value,
  898. // payload:JSON.stringify(data.payload)
  899. // }
  900. // console.log('answer',msg)
  901. // sendSocketData(msg)
  902. // } else {
  903. // console.log(resp)
  904. // }
  905. // })
  906. // }
  907. //--------------------------------------------------
  908. // 本人加入房间
  909. const joinRoom = () => {
  910. // 发送消息给房间里的其他人,有新人加进来了,由其他人生成offer返回给自己,自己再返回offer给其他人
  911. usersId.forEach((item: any) => {
  912. if(user.id!=item){
  913. sendcallingMsg(item);
  914. }
  915. })
  916. }
  917. const receiveJoin = (userId:any) => {
  918. if (userId) {
  919. let exist =existUser(userId)
  920. if (exist) {
  921. console.log("该用户已经在房间里:" + userId)
  922. return
  923. }
  924. console.log("新用户加入房间:" + userId)
  925. // 创建了与这个用户的连接
  926. createPeerConnection(userId)
  927. // 生成offer
  928. console.log("生成offer")
  929. webRTC.createOffer({
  930. userId: userId,
  931. setLocalDescription: false
  932. }, (resp:any) => {
  933. let flag = resp.flag
  934. if (flag) {
  935. let sessionDescription = resp.sessionDescription
  936. let type = sessionDescription.type
  937. let sdp = sessionDescription.sdp
  938. // 设置本地Description
  939. console.log("设置本地Description:" + JSON.stringify(sessionDescription))
  940. webRTC.setLocalDescription({
  941. userId: userId,
  942. type: type,
  943. sdp: sdp
  944. }, (localDescResp:any) => {
  945. let localFlag = localDescResp.flag
  946. if (localFlag) {
  947. // 将offer发送给对方
  948. console.log("发送offer:" + JSON.stringify(sdp))
  949. let data = {
  950. type: "SessionDescription",
  951. payload: {
  952. sdp:sdp,
  953. type: type
  954. }
  955. }
  956. let msg: Webrtc = {
  957. chatId: friendId.value,
  958. fromId: user.id,
  959. type: ChatType.FRIEND,
  960. msgtype:'offer',
  961. conetType:showVideo.value,
  962. payload:JSON.stringify(data.payload)
  963. }
  964. // 发送
  965. sendSocketData(msg)
  966. } else {
  967. console.log("setLocalDescription error:" + JSON.stringify(
  968. localDescResp))
  969. }
  970. })
  971. } else {
  972. console.log("createOffer error:" + JSON.stringify(resp))
  973. }
  974. })
  975. }
  976. }
  977. const existUser = (userId) => {
  978. for (let i = 0; i < otherPersons.length; i++) {
  979. let user = this.otherPersons[i]
  980. if (user.userId == userId) {
  981. return true
  982. }
  983. }
  984. return false
  985. }
  986. </script>
  987. <style>
  988. .AvatarImg{
  989. margin-top: 40rpx;
  990. width: 160rpx;
  991. height: 160rpx;
  992. border-radius: 10rpx;
  993. }
  994. .IncolumnC{
  995. display: flex;
  996. flex-direction: column;
  997. align-items: center;
  998. justify-content:center;
  999. }
  1000. .InrowC{
  1001. display: flex;
  1002. flex-direction:row;
  1003. align-items: center;
  1004. justify-content:center;
  1005. }
  1006. </style>