webRTCCallCtr.vue 25 KB

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