| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657 |
- <template>
- <page-meta :page-font-size="fontValue+'px'" :root-font-size="fontValue+'px'"></page-meta>
- <view>
- <cu-custom :isBack='true' >
- <template v-slot:content>
- <text class="text-jiachu text-black">在线通话</text>
- </template>
- </cu-custom>
- <view class="IncolumnC">
- <image class="AvatarImg" :src="friendAvatar" mode="scaleToFill"></image>
- <text v-if="friend.value" class="text-black text-lg"></text>
- <text class="text-black text-lg" style="margin-top: 10rpx;">{{friendName}}</text>
- <view class="InrowC" style="margin-top: 80rpx;">
- <text class="text-black text-lg">{{stateNote}}</text>
- <image style="width: 52rpx;height: 52rpx;margin-left: 6rpx;" src="/static/mine/loading2.gif" mode=""></image>
- </view>
- <view class="InrowC" style="margin-top: 300rpx;">
- <image v-if="!canClose" style="width:110rpx ;height: 110rpx;" src="/static/mine/icon_on.png" mode="scaleToFill" @click="acceptWebrtc"></image>
- <image v-if="canClose" style="width:110rpx ;height: 110rpx;" src="/static/mine/icon_off.png" mode="scaleToFill" @click="closeWebrtcBT"></image>
- <image v-if="speacker" style="margin-left: 50rpx;width:110rpx ;height: 110rpx;" src="/static/mine/ysq_on.png" mode="scaleToFill" @click="changeSpeack"></image>
- <image v-if="!speacker" style="margin-left: 50rpx;width:110rpx ;height: 110rpx;" src="/static/mine/ysq_off.png" mode="scaleToFill" @click="changeSpeack"></image>
- </view>
- </view>
- </view>
- </template>
- <script setup lang="ts">
- import {onLoad,onReady,onShow,onUnload} from '@dcloudio/uni-app';
- import {ref,watch} from 'vue'
- // import * as ASCIIUtils from '@/uni_modules/wrs-js-modbusCRCHex/js_sdk/wrs-ASCIIUtils.js';
- // import * as HexUtils from '@/uni_modules/wrs-js-modbusCRCHex/js_sdk/wrs-HexUtils.js';
- import {
- UTSWebRTC
- } from "@/uni_modules/wrs-uts-webrtc";
- import {
- UTSVoip,
- UTSLocalNotification,
- UTSVoipMgr
- } from "@/uni_modules/wrs-uts-voip"
-
- import MessageUtils from "@/utils/MessageUtils";
- import CuCustom from '@/colorui/components/cu-custom.vue'
- import UserApi from "@/api/UserApi";
- import {useUserStore} from '@/store/userStore'
- import {useWsStore} from "@/store/WsStore";
- import {storeToRefs} from "pinia";
- import type Webrtc from '@/mode/Webrtc';
- import ChatType from "@/utils/ChatType";
- import {usePeerStore} from "@/store/peerStore";
- import SendCode from '@/utils/SendCode'
- import Auth from "@/api/Auth";
- const fontValue=ref(Auth.getfontSize());
-
- let webRTC = new UTSWebRTC();
- let candidateList=[];
- let friendAvatar='/static/logo512.png';
- let friendName='';
- let stateNote =ref("正在呼叫");
- let audioObj=null;
- const timeCall=ref(0);
- const timer=ref();
-
- const wsStore = useWsStore();
- const peerStore = usePeerStore();
- const friendId = ref("");
- const friend = ref("");
-
- const startTime = ref(0)
- const isCaller = ref(false);
- const showVideo = ref(false);
- const speacker = ref(false);
- const canClose = ref(true);
- const user = useUserStore().getUser()
- const isConnect = ref(false)
- const videoIsOpen = ref(false)
-
- const hadClose = ref(false);
-
-
- const {isClose} = storeToRefs(peerStore)
- const {offer} = storeToRefs(peerStore)
- const {answer} = storeToRefs(peerStore)
-
- const {candidate} = storeToRefs(peerStore)
- const {isAccept} = storeToRefs(peerStore)
-
-
- watch(isAccept, (newVal) => {
- if (newVal) {
- timeCall.value=45;
- getoffer();
- }
- })
- watch(isClose, (newVal) => {
- console.log('isCloseisClose',newVal)
- if (newVal) {
- uni.navigateBack()
- }
- })
-
- watch(offer, (newVal) => {
- console.log('offer',isCaller);
- if (newVal) {//收到answeroffer
- recOffer();
- }
- })
-
- watch(answer, (newVal) => {
- if (newVal) {//收到answer
- recAnswer();
- }
- })
-
- watch(candidate, (newVal) => {
- if (newVal) {//收到candidate
- console.log('candidate');
- var list = JSON.parse(newVal);
- list.forEach((item) => {
- webRTC.addIceCandidate({
- sdp: item.candidate,
- sdpMLineIndex: item.sdpMLineIndex,
- sdpMid: item.sdpMid
- }, (resp) => {
- console.log("addIceCandidate result:" + JSON.stringify(resp))
- })
- })
- }
- sendCandidate();
- })
-
- const chaoshipanduan = () => {
- timeCall.value=45;
- timer.value = setInterval(() => {
- timeCall.value=timeCall.value-1;
- if(timeCall.value==0&&!isConnect.value){
- MessageUtils.message('暂时无法连接,请稍后重试!')
- }
- else if(isConnect.value){
- clearInterval(timer.value);//正常接通
- return;
- }
- else if(timeCall.value<-2&&!isConnect.value){
- uni.navigateBack();
- }
- }, 1000);
- }
-
- const audioObjstart = () => {
- audioObj=uni.createInnerAudioContext();
- audioObj.loop=true;
- audioObj.volume=0.2;
- audioObj.src='/hybrid/html/images/calling.mp3';
- audioObj.play();
-
- setTimeout(function() {
- // 这里写要延时执行的代码
- if(showVideo.value){
- console.log('onReady1');
- webRTC.setSpeakerEnable(true)
- speacker.value=true;
- }
- else{
- console.log('onReady2');
- webRTC.setSpeakerEnable(false)
- }
- }, 300);
- }
-
- const audioObjstop = () => {
- if(audioObj){
- audioObj.stop();
- }
- }
-
- onShow(()=>{
- // console.log('onShow',videoIsOpen.value)
- if(videoIsOpen.value){
- //closeWebrtc();
- uni.navigateBack();
- return;
- }
- let state = UTSVoipMgr.getApplicationState()
- // console.log('getApplicationstate2-------',state);
- if(state!=2){
- if(uni.getSystemInfoSync().platform == "ios"&&!isCaller.value){
- //let provider = new UTSCXProvider()
- UTSVoipMgr.endCall({
- uuid: uni.getStorageSync("voip_UUID")
- }, (resp: any)=>{
- console.log(JSON.stringify(resp))
- })
- }
- initData();
- getfriendMsg();
- audioObjstart();
- setTimeout(function() {
- // 这里写要延时执行
- if(isCaller.value){//主动发起通话
- }
- else{
- acceptWebrtc();//自动接听
- }
- }, 1500);
- }
- })
- onReady(()=>{
- console.log('onReady');
- chaoshipanduan();
- });
- onLoad((opt) => {
- console.log('onLoad')
- usePeerStore().updateBusyStatus(true)
- usePeerStore().updateCloseStatus(false)
- if(typeof opt?.isCaller === 'string'){
- isCaller.value = opt?.isCaller === 'true'
- if(isCaller.value){
- canClose.value = true;
- }
- console.log('isCaller',canClose);
- }
- if(typeof opt?.showVideo === 'string'){
- showVideo.value = opt?.showVideo === 'true'
- }
- candidateList=[];
- friendId.value = opt?.friendId;
- });
-
- const initData = () =>{
- webRTC.onCallback((resp) => {
- let opt = resp.opt
- //console.log(opt);
- switch (opt) {
- case "didChangeIceConnectionState": {
- let state = resp.state
- console.log(state);
- if(state==4||state==5||state==6){
- stateNote.value ='连接已断开';
- }
- if(state==2){
- console.log('已连接')
- audioObjstop();
- isConnect.value = true
- startTime.value = new Date().getTime()
- stateNote.value ='已连接';
- if(showVideo.value&&!videoIsOpen.value){//打开视频
- videoIsOpen.value=true;
- webRTC.setSpeakerEnable(true)
- // uni.navigateTo({
- // url:'/imcall/iOSVideoView'
- // })
- }
- }
- // 0:RTCIceConnectionStateNew,
- // 1: RTCIceConnectionStateChecking,
- // 2:RTCIceConnectionStateConnected,
- // 3:RTCIceConnectionStateCompleted,
- // 4:RTCIceConnectionStateFailed,
- // 5:RTCIceConnectionStateDisconnected,
- // 6:RTCIceConnectionStateClosed,
- // 7: RTCIceConnectionStateCount,
- }
-
- break;
- case "didChangeIceGatheringState": {
- let state = resp.state
- // 0: RTCIceGatheringStateNew
- // 1: RTCIceGatheringStateGathering
- // 2: RTCIceGatheringStateComplete
- }
- break;
- case "didChangeSignalingState": {
- let state = resp.state
- // 0: RTCSignalingStateStable,
- // 1:RTCSignalingStateHaveLocalOffer,
- // 2:RTCSignalingStateHaveLocalPrAnswer,
- // 3:RTCSignalingStateHaveRemoteOffer,
- // 4:RTCSignalingStateHaveRemotePrAnswer,
- // 5: RTCSignalingStateClosed,
- }
- break;
- // 收集本机生成的Candidate
- case "didGenerateCandidate":
- //this.localCandidate = true
- let candidate = resp.candidate
- //console.log('iosCandidate',candidate)
- let data = {
- candidate: candidate.sdp,
- sdpMLineIndex: candidate.sdpMLineIndex,
- sdpMid: candidate.sdpMid,
- }
- candidateList.push(data);
- break;
- default:
- break;
- }
- })
-
- let params = {
- iceServers:[],
- sdpSemantics:1,
- continualGatheringPolicy:1,
- constraints:{}
- }
- // iceServer目前支持2种格式,更多格式请联系作者
- // 1.
- // {
- // urls: ["xxx"]
- // }
- // 2.
- // {
- // urls: ["xxx"],
- // username: "xxx",
- // credential: "xx"
- // }
-
- params.iceServers = [{
- urls: ["stun:203.175.169.52:3478",
- "turn:203.175.169.52:3478"
- ],
- username: 'aaaaa',
- credential: 'bbbbb'
- }
- ]
- params.sdpSemantics = 1 // 0: RTCSdpSemanticsPlanB 1:RTCSdpSemanticsUnifiedPlan
- params.continualGatheringPolicy =
- 1 // 0: RTCContinualGatheringPolicyGatherOnce 1: RTCContinualGatheringPolicyGatherContinually
- params.constraints = {
- mandatory: {},
- optional: {
- DtlsSrtpKeyAgreement: "true"
- }
- }
- console.log(params);
- let suc = webRTC.peerConnection(params)
- console.log(suc);
- if (suc) {
- // 添加音频
- webRTC.addAudioTrack({
- trackId: "audio0",
- streamIds: ["stream"]
- })
- // 添加视频
- webRTC.addVideoTrack({
- trackId: "video0",
- streamIds: ["stream"]
- })
- // 添加数据channel
- webRTC.createDataChannel({
- label: "WebRTCData"
- })
- // 配置音频
- webRTC.configureAudioSession({
- category: "playAndRecord",
- mode: "voiceChat"
- })
- } else {
- console.log("peerConnection fail")
- }
- };
-
- const getfriendMsg = () => {
- UserApi.getUser(friendId.value).then((res) => {
- friend.value = res.data
- if (friend.value) {
- friendName=friend.value.name;
- friendAvatar=encodeURI(friend.value.avatar);
- if(isCaller.value){//主动发起通话
- sendcallingMsg();
- }
- else{
- //acceptWebrtc();//自动接听
- }
- }
- })
- }
-
- const changeSpeack = () => {
- if(speacker.value){
- speacker.value=false;
- }
- else{
- speacker.value=true;
- }
- console.log('setAudioEnabled',speacker.value)
- webRTC.setSpeakerEnable(speacker.value)
- }
-
- const acceptWebrtc = () => {
- console.log('acceptWebrtc');
- startTime.value = new Date().getTime()
- //给自己发一份忙碌状态,多个客户端同一个人不能同时接受,需要客户端接受后,其他客户端就关闭
- let data={
- code: SendCode.WEBRTC_BUSY,
- message: {
- chatId:friendId.value,
- fromId: user.id,
- type: ChatType.FRIEND,
- msgtype:'accept',
- video: showVideo.value,
- }
- }
- console.log(data);
- useWsStore().send(JSON.stringify(data));
- canClose.value = true;
- }
- const closeWebrtcBT = () => {
- uni.navigateBack();
- }
- const closeWebrtc = () => {
- if (user.id) {
- const closeMessage = {
- code: SendCode.WEBRTC_CLOSE,
- message: {
- chatId:friendId.value,
- fromId: user.id,
- timestamp: new Date().getTime(),
- type: ChatType.FRIEND,
- msgtype:'close'
- }
- }
- wsStore.send(JSON.stringify(closeMessage))
- hadClose.value=true;
- console.log('发送关闭消息', closeMessage)
- //发起方才有发送视频结果消息的权限
- if (isCaller.value) {
- //界面展示视频消息情况,例如:对方是否接受了视频通话,通话时长
- const message= {
- id:null,
- localtime:null,
- mine:true,
- messageType:SendCode.WEBRTC_result,
- chatId:friendId.value,
- fromId: user.id,
- timestamp: new Date().getTime(),
- type: ChatType.FRIEND,
- result: isConnect.value,
- video: showVideo.value,
- duration: isConnect.value ? new Date().getTime() - startTime.value : 0
- }
- console.log(message)
- wsStore.sendWEBRTCresult(message);
- }
- }
- }
- const sendSocketData = (data:any) => {
- wsStore.sendWEBRTC(data)
- console.log('发送消息', data);
- }
-
- const sendCandidate = () =>{
- let msg: Webrtc = {
- chatId: friendId.value,
- fromId: user.id,
- type: ChatType.FRIEND,
- msgtype:'candidate',
- conetType:showVideo.value,
- payload:JSON.stringify(candidateList)
- }
- console.log("将本机candidate发送给对方")
- sendSocketData(msg);
- }
-
- //主动发起通话操作,isCaller为true-----------------------------
- const sendcallingMsg = () => {
- console.log('sendcallingMsg');
- let msg: Webrtc = {
- chatId:friendId.value,
- fromId: user.id,
- type: ChatType.FRIEND,
- msgtype:'calling',
- conetType:showVideo.value,
- timestamp: new Date().getTime(),
- payload:''
- }
- let data={
- code:SendCode.WEBRTC_CALL,
- message: msg
- }
- console.log('sendcallingMsg',data);
- useWsStore().send(JSON.stringify(data))
- }
- const getoffer = () => {
- var videoV="false";
- if(showVideo.value){
- videoV="true";
- }
- webRTC.offer({
- OfferToReceiveAudio: "true",
- OfferToReceiveVideo:videoV
- }, (resp:any) => {
- let flag = resp.flag
- if (flag) {
- let sdp = resp.sdp
- console.log("发送offer sdp",resp)
- let type = ""
- switch (sdp.type) {
- case 0:
- type = "offer"
- break;
- case 1:
- type = "prAnswer"
- break;
- case 2:
- type = "answer"
- break;
- case 3:
- type = "rollback"
- break;
- default:
- break;
- }
- let data = {
- type: "SessionDescription",
- payload: {
- sdp: sdp.sdp,
- type: type
- }
- }
- let msg: Webrtc = {
- chatId: friendId.value,
- fromId: user.id,
- type: ChatType.FRIEND,
- msgtype:'offer',
- conetType:showVideo.value,
- payload:JSON.stringify(data.payload)
- }
- // 发送给接听方
- sendSocketData(msg)
- } else {
- console.log(resp)
- }
- })
- }
- onUnload(()=>{
- clearInterval(timer.value);//正常接通
- audioObjstop();
- if(!hadClose.value){
- closeWebrtc();
- }
- webRTC.close();
- peerStore.setCallId(undefined);
- peerStore.setOffer(undefined);
- peerStore.setAnswer(undefined);
- peerStore.setCandidate(undefined);
- peerStore.updateBusyStatus(false);
- peerStore.updateCloseStatus(false);
- peerStore.setIsAccept(false);
- });
- //收到answer
- const recAnswer = () => {
- let answer=JSON.parse(peerStore.offer)
- console.log('answeroffer',answer);
- webRTC.setRemoteDescription({
- type: 2,
- sdp:answer.sdp
- }, (resp:any) => {
- if(resp.flag){
- sendCandidate();
- }
- console.log("setRemoteDescription result:" + JSON.stringify(resp))
- })
- }
-
- //被动接听通话操作,isCaller为false-----------------------------
- //收到recOffer
- const recOffer = () => {
-
- let payload=JSON.parse(peerStore.offer)
- console.log('recOffer1',payload);
- // let payload2=JSON.parse(payload.payload)
- // console.log('recOffer2',payload2);
- webRTC.setRemoteDescription({
- type: 0,
- sdp: payload.sdp
- }, (resp:any) => {
- console.log("setRemoteDescription result:" + JSON.stringify(resp))
- cranswer();
- })
- }
-
- const cranswer = () => {
- var videoV="false";
- if(showVideo.value){
- videoV="true";
- }
- webRTC.answer({
- OfferToReceiveAudio: "true",
- OfferToReceiveVideo:videoV
- }, (resp) => {
- let flag = resp.flag
- if (flag) {
- let sdp = resp.sdp
- let type = ""
- switch (sdp.type) {
- case 0:
- type = "offer"
- break;
- case 1:
- type = "prAnswer"
- break;
- case 2:
- type = "answer"
- break;
- case 3:
- type = "rollback"
- break;
- default:
- break;
- }
- let data = {
- type: "SessionDescription",
- payload: {
- sdp: sdp.sdp,
- type: type
- }
- }
- // 发送给呼叫方
- let msg: Webrtc = {
- chatId:friendId.value,
- fromId:user.id,
- type: ChatType.FRIEND,
- msgtype:'answer',
- conetType:showVideo.value,
- payload:JSON.stringify(data.payload)
- }
- console.log('answer',msg)
- sendSocketData(msg)
- } else {
- console.log(resp)
- }
- })
- }
-
-
- </script>
- <style>
- .AvatarImg{
- margin-top: 40rpx;
- width: 160rpx;
- height: 160rpx;
- border-radius: 10rpx;
- }
- .IncolumnC{
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content:center;
- }
- .InrowC{
- display: flex;
- flex-direction:row;
- align-items: center;
- justify-content:center;
- }
- </style>
|