import React, { FC, useState, useEffect } from 'react' import $dp from 'dataProvider' import auth from 'utils/auth' import i18n from 'i18n' import audioicon from 'theme/images/audio.png' import audiocloseicon from 'theme/images/audio_close.png' import cameraicon from 'theme/images/camera.png' import cameracloseicon from 'theme/images/camera_close.png' import { Modal, message } from 'components/ui-components' import { getUCNickName } from 'utils/ucUser' import { showAlert, initialization, getSubscribeInfo, setConfigRemote, receivePublishManual } from './utils' import styles from './style.module.scss' interface IWebRTCBodyProps { channelId: string ownerId: string onOwnerLeave: ()=>void } const WebRTC: FC<IWebRTCBodyProps> = (props) => { const { channelId, ownerId, onOwnerLeave } = props const [openAudia, setOpenAudia] = useState(true) const [openCamera, setOpenCamera] = useState(true) let publisherList: any[] let aliToken: any let isCameraEnable: boolean = true let currentUser: any = auth.getAuth() let nickName = getUCNickName(currentUser) let t = i18n.getFixedT(null, 'message') const aliWebrtc = window.aliWebrtc function removeDom(userid: any) { } function compareIsOwner(compareOwnerId: string) { let newOwnerId if (compareOwnerId.length > 1) { newOwnerId = compareOwnerId.substr(0, compareOwnerId.length - 1) } return ownerId === newOwnerId } function detelePublisher(userId: any) { let index = (publisherList as any).getIndexByProprety(userId, 'userId') if (index !== -1) { publisherList.splice(index, 1) detelePublisher(userId) } else { console.log('未找到之前的推流数据')// 删除推流用户 } } function updateUserList() { let videoList = document.getElementById('remote-user-list-video') let userList = aliWebrtc.getUserList() if (videoList && videoList.hasChildNodes()) { let childList = videoList.childNodes for (let i = childList.length - 1; i >= 1; i--) { let childDiv = childList[i] let currentId = (childDiv as HTMLElement).id.substr(9) let isFind = false for (let j = 0; j < userList.length; j++) { let currentUser = userList[j] if (currentId === currentUser.userId) { isFind = true break } } if (!isFind) { videoList.removeChild(childList[i]) } } } // let frg = document.createDocumentFragment() userList.forEach((user: any) => { let isFind = false let videoList = document.getElementById('remote-user-list-video') if (videoList && videoList.hasChildNodes()) { let childList = videoList.childNodes for (let i = childList.length - 1; i >= 1; i--) { let childDiv = childList[i] let currentId = (childDiv as HTMLElement).id.substr(9) if (currentId === user.userId) { isFind = true break } } } if (!isFind && videoList) { if (user.userId !== aliToken.userid) { if (!compareIsOwner(user.userId)) { let videoDiv = document.createElement('div') videoDiv.className = styles['video-box'] videoDiv.id = `video-box${user.userId}` let videoText = document.createElement('div') videoText = document.createElement('div') videoText.className = styles['video-box-text'] videoDiv.appendChild(videoText) let videoName = document.createElement('p') videoName.align = 'center' videoName.className = styles['video-text-p'] videoName.innerHTML = `${user.displayName}` videoName.id = `videoName${user.userId}` videoText.appendChild(videoName) let videoParent = document.createElement('div') videoParent.className = styles['video-box-parent'] videoDiv.appendChild(videoParent) let videoEle = document.createElement('video') videoEle.autoplay = true // videoEle.playsinline = true videoEle.controls = false videoEle.width = 146 videoEle.height = 110 videoEle.style.marginTop = '5' videoEle.id = `video${user.userId}` videoParent.appendChild(videoEle) let leftNameDiv = document.createElement('div') leftNameDiv.className = styles['video-box-text-2'] videoDiv.appendChild(leftNameDiv) leftNameDiv.id = `videoBoxText2${user.userId}` let leftNamePara = document.createElement('p') leftNamePara.className = styles['video-text-p-2'] leftNamePara.id = `videoName2${user.userId}` leftNameDiv.appendChild(leftNamePara) leftNameDiv.style.display = 'none' videoList.appendChild(videoDiv) } } } }) } function unSubn(streamConfigWithPublisherInfo: any) { if (streamConfigWithPublisherInfo.subscribed) { console.log('已经订阅') return } console.log(`----onPublisher${streamConfigWithPublisherInfo.userId} ${streamConfigWithPublisherInfo.displayName}`) receivePublishManual(streamConfigWithPublisherInfo) .then((re: any) => { if (compareIsOwner(streamConfigWithPublisherInfo.userId)) { let videoEleID = 'local-video-window' let video = document.getElementById(videoEleID) // let videoNameEleID = 'videoName' + publisher.userId // let p = document.getElementById(videoNameEleID) // p.innerHTML = publisher.displayName if (streamConfigWithPublisherInfo.label !== 'sophon_video_screen_share') { aliWebrtc.setDisplayRemoteVideo(streamConfigWithPublisherInfo.userId, video, 1) } else { aliWebrtc.setDisplayRemoteVideo(streamConfigWithPublisherInfo.userId, video, 2) } // aliWebrtc.setDisplayRemoteVideo(streamConfigWithPublisherInfo.userId, video, 1) } else { let videoEleID = `video${streamConfigWithPublisherInfo.userId}` let video = document.getElementById(videoEleID) let videoNameEleID = `videoName${streamConfigWithPublisherInfo.userId}` let p = document.getElementById(videoNameEleID) let videoNameEleID2 = `videoName2${streamConfigWithPublisherInfo.userId}` let p2 = document.getElementById(videoNameEleID2) if (p) { p.innerHTML = streamConfigWithPublisherInfo.displayName } if (p2) { p2.innerHTML = streamConfigWithPublisherInfo.displayName } let videoBoxText2 = `videoBoxText2${streamConfigWithPublisherInfo.userId}` let videoBoxText2Ele = document.getElementById(videoBoxText2) let newpublisher = aliWebrtc.getUserInfo(re) if (videoBoxText2Ele) { for (let stream of newpublisher.streamConfigs) { if (stream.label === 'sophon_video_camera_large') { if (stream.state === 'active') { videoBoxText2Ele.style.display = 'block' } else { videoBoxText2Ele.style.display = 'none' } break } } } if (streamConfigWithPublisherInfo.label !== 'sophon_video_screen_share') { aliWebrtc.setDisplayRemoteVideo(streamConfigWithPublisherInfo.userId, video, 1) } else { aliWebrtc.setDisplayRemoteVideo(streamConfigWithPublisherInfo.userId, video, 2) } // aliWebrtc.setDisplayRemoteVideo(streamConfigWithPublisherInfo.userId, video, 1) } }).catch((err: any) => { console.log(`订阅断开 重新订阅失败${err}`) detelePublisher(streamConfigWithPublisherInfo.userId) removeDom(streamConfigWithPublisherInfo.userId) }) } function autoSub(publisher: any, label: string) { var i = publisher.streamConfigs.findIndex(((e:any) => e.label === label && e.state === 'active' && e.subscribed === false )) if (i > -1) { var o = publisher.streamConfigs[i] o.userId = publisher.userId o.displayName = publisher.displayName unSubn(o) } } function updatePublisherStream(publisher: any, index: number) { let oldStreamConfigs = JSON.parse(JSON.stringify(publisherList[index].streamConfigs)) let newStreamConfigs = publisher.streamConfigs let subscribeInfo = getSubscribeInfo(publisher.userId) oldStreamConfigs.forEach((v: any, i: any, a: any) => { let newStream = newStreamConfigs.getObjByProprety(v.label, 'label') // 判断流状态改变了 但不确定我们是否订阅了该流 if (v.state !== newStream.state) { console.log(`流的状态变了${v.label}`, v, v.type, `>${v.state}>>${newStream.state}>`, newStream, subscribeInfo) // 并且要取消订阅某个流,不然就不能再次订阅了 subscribeInfo.subscribeInfoArr.forEach((sv) => { if (v.label === sv.label) { console.log('setConfigRemote取消订阅调用[api]:subscribe', publisher.userId, sv.type, sv.label) setConfigRemote(publisher.userId, sv.type, sv.label).then((re: any) => { // 移除dom removeDom(publisher.userId) }).catch((error: any) => { console.error('流的状态变了重新订阅出问题', error) }) } }) } }) publisherList.splice(index, 1, publisher) setTimeout(() => { autoSub(publisher, 'sophon_video_screen_share') autoSub(publisher, 'sophon_video_camera_large') }, 2000) } function init() { /** * remote用户加入房间 onJoin * 更新在线用户列表 */ aliWebrtc.on('onJoin', (publisher: any) => { aliWebrtc.configRemoteAudio(publisher.userId, false) aliWebrtc.configRemoteCameraTrack(publisher.userId, false, false) if (publisher.userId && !compareIsOwner(publisher.userId)) { console.log(`join: ${publisher.userId}`) updateUserList() } // 重置订阅状态 // 默认订阅远端音频和视频大流,但需要调用subscribe才能生效 // 这里取消默认订阅,根据需求进行订阅 // aliWebrtc.configRemoteAudio(publisher.userId, true) // aliWebrtc.configRemoteCameraTrack(publisher.userId, true, true) // showAlert(publisher.displayName + '加入房间','success') // console.log(`${publisher.displayName}加入房间`) }) aliWebrtc.on('onNotify', (data: any) => { console.log('用户状态回调') console.log(data) }) /** * remote流发布事件 onPublish * 将该用户新增到推流列表 * 若该用户已存在推流列表,则进行状态更新 */ aliWebrtc.on('onPublisher', (publisher: any) => { console.log('onPublisher', publisher) let index = (publisherList as any).getIndexByProprety(publisher.userId, 'userId') if (index === -1) { // 新增 publisherList.push(publisher) if (publisher.userId !== aliToken.userid) { const o = publisher.streamConfigs.findIndex(((e: any) => e.type === 'audio' && e.state === 'active' )) const n = publisher.streamConfigs.findIndex(((e: any) => e.label === 'sophon_video_screen_share' && e.state === 'active' )) let r = publisher.streamConfigs.findIndex(((e: any) => e.label === 'sophon_video_camera_large' && e.state === 'active' )) if (r === -1 && (r = publisher.streamConfigs.findIndex(((e: any) => e.label === 'sophon_video_camera_small' && e.state === 'active' ))) > -1 && o > -1) { const a = publisher.streamConfigs[o] a.userId = publisher.userId a.displayName = publisher.displayName unSubn(a) } if (n > -1) { const s = publisher.streamConfigs[n] s.userId = publisher.userId s.displayName = publisher.displayName unSubn(s) } if (r > -1) { const c = publisher.streamConfigs[r] c.userId = publisher.userId c.displayName = publisher.displayName unSubn(c) } } } else { // 流状态更新 updatePublisherStream(publisher, index) } }) /** * remote流结束发布事件 onUnPublisher * 推流列表删除该用户 * 移除用户视图 * 初始化订阅状态 */ aliWebrtc.on('onUnPublisher', (publisher: any) => { console.log('onUnPublisher', publisher) detelePublisher(publisher.userId) removeDom(publisher.userId) initialization(publisher.userId) }) /** * 检测到用户离开频道 * 更新用户列表 * 移除用户视图 */ aliWebrtc.on('onLeave', (publisher: any) => { if (publisher.userId.includes(ownerId)) { onOwnerLeave() } initialization(publisher.userId) updateUserList() removeDom(publisher.userId) // message.info(`${publisher.displayName}离开房间`) }) } function getConfigAndJoinRoom() { let userId: string if (currentUser && currentUser.user_id) { userId = `${String(currentUser.user_id)}3` } else { return } $dp.aliRTC.channelToken .replace({ channel_id: channelId, user_id: userId }) .get() .then((token: any) => { aliToken = token aliToken.channel = token.channel_id aliToken.userid = token.user_id joinRoom(aliToken) }) .catch((error:any) => { console.log(error) message.warning('aliwebrtc token get failed!') }) } function doJoinRoomProc(authInfo: any) { aliWebrtc.joinChannel(authInfo, nickName).then(() => { // showAlert('加入房间成功', 'success', 0) // 4. 发布本地流 aliWebrtc.configLocalAudioPublish = true aliWebrtc.configLocalCameraPublish = isCameraEnable aliWebrtc.publish().then((res: any) => { // Msg.warn(t('webrtc success')) // setTimeout(() => { // console.log('发布流成功') // }, 1000) console.log('发布流成功') }, (error: any) => { let errorTitle = `[推流失败]${error.message}` console.log(errorTitle) // $('.streamType').show() showAlert(`[推流失败]${error.message}`, 'danger', 0) message.warning(`[推流失败]${error.message}`) }) }).catch((error: any) => { // showAlert('[加入房间失败]' + error.message, 'danger',0) message.warning(`[加入房间失败]${error.message}`) }) } function joinRoom(authInfo: any) { // 1.预览 var localVideo = document.getElementById('local-video-currentuser') // var localVideo = $('.local-video video') aliWebrtc.startPreview(localVideo).then((obj: any) => { showAlert('----[开启预览成功]', 'danger', 0) setTimeout(() => { let videoLocalELe = document.getElementById('local-video-currentuser') // console.log(videoLocalELe.videoWidth, videoLocalELe.videoHeight) let videoWidth: number = (videoLocalELe as any).videoWidth let videoHeight: number = (videoLocalELe as any).videoHeight if (videoWidth < 50 || videoHeight < 50) { setTimeout(() => { videoLocalELe = document.getElementById('local-video-currentuser') videoWidth = (videoLocalELe as any).videoWidth videoHeight = (videoLocalELe as any).videoHeight console.log(videoWidth, videoHeight) if (videoWidth < 50 || videoHeight < 50) { isCameraEnable = false // this.setState({ // openCamera: false // }) let name2 = document.getElementById('video-box-text-2') if (name2) { name2.style.display = 'none' } } doJoinRoomProc(authInfo) }, 2000) } else { doJoinRoomProc(authInfo) } }, 2000) }).catch((error: any) => { showAlert(`[开启预览失败]${error.message}`, 'danger', 0) isCameraEnable = false // this.setState({ // openCamera: false // }) let name2 = document.getElementById('video-box-text-2') if (name2) { name2.style.display = 'none' } doJoinRoomProc(authInfo) }) } function audioAction() { if (!openAudia) { console.log('open Audia') // window.aliWebrtc.enableHighDefinitionPreview(true) aliWebrtc.configLocalAudioPublish = true aliWebrtc.publish().then((res:any) => { setTimeout(() => { console.log('发布流成功') }, 1000) }, (error:any) => { // $('.streamType').show() showAlert(`[推流失败]${error.message}`, 'danger', 0) }) setOpenAudia(true) } else { console.log('close Audia') // window.aliWebrtc.enableHighDefinitionPreview(false) aliWebrtc.configLocalAudioPublish = false aliWebrtc.unPublish().then(() => { aliWebrtc.publish().then((res:any) => { setTimeout(() => { console.log('发布流成功') }, 1000) }, (error:any) => { // $('.streamType').show() showAlert(`[推流失败]${error.message}`, 'danger', 0) }) }, (error:any) => { console.log(error.message) }) setOpenAudia(false) } } function cameraAction() { if (!openCamera) { console.log('open camera') if (!isCameraEnable) { // Modal.warning({ title: t('bad camera') }) return } let winTips = document.getElementById('local-video-currentuser-parent') if (winTips) { winTips.style.display = 'block' } let name2 = document.getElementById('video-box-text-2') if (name2) { name2.style.display = 'block' } aliWebrtc.configLocalCameraPublish = true aliWebrtc.publish().then((res:any) => { setTimeout(() => { console.log('发布流成功') }, 2000) }, (error:any) => { showAlert(`[推流失败]${error.message}`, 'danger', 0) }) setOpenCamera(true) } else { console.log('close camera') let winTips = document.getElementById('local-video-currentuser-parent') if (winTips) { winTips.style.display = 'none' } let name2 = document.getElementById('video-box-text-2') if (name2) { name2.style.display = 'none' } aliWebrtc.configLocalCameraPublish = false aliWebrtc.unPublish().then(() => { aliWebrtc.publish().then((res:any) => { setTimeout(() => { console.log('发布流成功') }, 2000) }, (error:any) => { // $('.streamType').show() showAlert(`[推流失败]${error.message}`, 'danger', 0) }) }, (error:any) => { console.log(error.message) }) setOpenCamera(false) } } function createAliyun() { publisherList = [] /** * AliWebRTC isSupport检测 */ aliWebrtc.isSupport().then((re: any) => { console.log(re) init() getConfigAndJoinRoom() }).catch((error: any) => { // self.sendCmdMsg(NTF_MSG_TYPE.LIVE_CANCEL_APPLY_CONNECT, LIVE_CONNECT_TYPE.APPLY) // let message // $bus.preprocess.publish(CTL_MSG_TYPE.LIVE_CMD_MSG, { // type: NTF_MSG_TYPE.LIVE_CANCEL_APPLY_CONNECT, // data: {} // }) // if (!error.audioDevice) { // message = this.t('audio not found') // } else if (!error.videoDevice) { // message = this.t('video not found') // } else { // message = error.message // } // Modal.warning({ // title: message, // onOK() { // } // }) }) } useEffect(() => { // runningMarquee() createAliyun() return () => { console.log('----container leavechannel') aliWebrtc.stopPreview().then().catch() aliWebrtc.leaveChannel() } }, []) return ( <div> <div className={styles['remote-user-list']}> <div className={styles['remote-user-list-video']} id="remote-user-list-video"> <div className={styles['video-box']}> <div className={styles['video-box-text']}> <p className={styles['video-text-p']}>{nickName}</p> </div> <div className={styles['video-box-parent']} id="local-video-currentuser-parent"> <video id="local-video-currentuser" autoPlay controls={false} width="146px" height="110px" /> </div> <div className={styles['video-box-text-2']} id="video-box-text-2"> <p className={styles['video-text-p-2']}>{nickName}</p> </div> </div> </div> </div> <div className={styles['local-video']}> <div className={styles['local-video-window-close']} id="local-video-window-close"> <div className={styles['local-video-window-close-tips']}> <h1 className={styles['local-video-window-close-tips-title']}>{t('closed camera')}</h1> </div> </div> <div className={styles['local-video-window-parent']}> <video id="local-video-window" autoPlay controls={false} width="100%" height="100%"> </video> </div> </div> <div className={styles['bottom-view']}> <div className={styles['operation-container-head']} onClick={() => audioAction()}><img className={styles.img} src={openAudia ? audioicon : audiocloseicon} width="30px" /></div> <div className={styles['operation-container-head']} onClick={() => cameraAction()}><img className={styles.img} src={openCamera ? cameraicon : cameracloseicon} width="30px" margin-left="-15px" /></div> {/* <div className={styles['operation-container-righticon']} type="primary" onClick={() => this.audioAction()}><img className={styles['img']} src={this.state.openAudia ? audioicon : audiocloseicon} align="left" width="30px" /></div> <div className={styles['operation-container-head']} type="primary" onClick={() => this.cameraAction()}><img className={styles['img']} src={this.state.openCamera ? cameraicon : cameracloseicon} width="30px" margin-left="-15px" /></div> */} </div> </div> ) } export default WebRTC