import React, {Component, PureComponent} from 'react'; import { StyleSheet, Text, View, TouchableOpacity, Image, Dimensions, Modal, Platform, NativeModules } from 'react-native'; import {RtcEngine, AgoraView} from 'react-native-agora'; import { APPID, isIphoneX, isIphoneXR } from '../utils'; const {Agora} = NativeModules; if (!Agora) { throw new Error("Agora load failed in react-native, please check ur compiler environments"); } const { FPS30, FixedLandscape, Host, AudioProfileDefault, AudioScenarioDefault, } = Agora; const BtnEndCall = () => require('../assets/btn_endcall.png'); const BtnMute = () => require('../assets/btn_mute.png'); const BtnSpeaker = () => require('../assets/btn_speaker.png'); const BtnSwitchCamera = () => require('../assets/btn_switch_camera.png'); const BtnVideo = () => require('../assets/btn_video.png'); const EnableCamera = () => require('../assets/enable_camera.png'); const DisableCamera = () => require('../assets/disable_camera.png'); const EnablePhotoflash = () => require('../assets/enable_photoflash.png'); const DisablePhotoflash = () => require('../assets/disable_photoflash.png'); const IconMuted = () => require('../assets/icon_muted.png'); const IconSpeaker = () => require('../assets/icon_speaker.png'); const {width, height} = Dimensions.get('window'); const safeTop = (top) => (isIphoneX(Platform, width, height) ? (top + 88) : (isIphoneXR(Platform, width, height) ? ( top + 64 ) : top) ); const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#F4F4F4' }, absView: { position: 'absolute', top: safeTop(0), left: 0, right: 0, bottom: 0, justifyContent: 'space-between', }, videoView: { padding: 5, flexWrap: 'wrap', flexDirection: 'row', zIndex: 100 }, localView: { flex: 1 }, remoteView: { width: (width - 40) / 3, height: (width - 40) / 3, margin: 5 }, bottomView: { padding: 20, flexDirection: 'row', justifyContent: 'space-around' } }); class OperateButton extends PureComponent { render() { const {onPress, source, style, imgStyle = {width: 50, height: 50}} = this.props; return ( ) } } type Props = { channelProfile: Number, channelName: String, videoProfile: Number, clientRole: Number, onCancel: Function, uid: Number, } export default class AgoraComponent extends Component { state = { peerIds: [], joinSucceed: false, isSpeak: true, isMute: false, isCameraTorch: false, disableVideo: false, hideButton: false, visible: false, selectedUid: undefined, }; componentWillMount () { const config = { appid: APPID, channelProfile: this.props.channelProfile, videoProfile: this.props.videoProfile, clientRole: this.props.clientRole, videoEncoderConfig: { width: 360, height: 480, bitrate: 1, frameRate: FPS30, orientationMode: FixedLandscape, }, clientRole: Host, audioProfile: AudioProfileDefault, audioScenario: AudioScenarioDefault }; RtcEngine.on('firstRemoteVideoDecoded', (data) => { console.log('[RtcEngine] onFirstRemoteVideoDecoded', data); }); RtcEngine.on('userJoined', (data) => { console.log('[RtcEngine] onUserJoined', data); const {peerIds} = this.state; if (peerIds.indexOf(data.uid) === -1) { this.setState({ peerIds: [...peerIds, data.uid] }) } }); RtcEngine.on('userOffline', (data) => { console.log('[RtcEngine] onUserOffline', data); this.setState({ peerIds: this.state.peerIds.filter(uid => uid !== data.uid) }) }); RtcEngine.on('joinChannelSuccess', (data) => { console.log('[RtcEngine] onJoinChannelSuccess', data); RtcEngine.startPreview(); this.setState({ joinSucceed: true }) }); RtcEngine.on('audioVolumeIndication', (data) => { console.log('[RtcEngine] onAudioVolumeIndication', data); }); RtcEngine.on('clientRoleChanged', (data) => { console.log("[RtcEngine] onClientRoleChanged", data); }) RtcEngine.on('error', (data) => { if (data.error === 17) { RtcEngine.leaveChannel().then(_ => { RtcEngine.destroy(); this.props.onCancel(data); }); } }) console.log("[CONFIG]", JSON.stringify(config)); console.log("[CONFIG.encoderConfig", config.videoEncoderConfig); RtcEngine.init(config); } componentDidMount () { RtcEngine.getSdkVersion((version) => { console.log('[RtcEngine] getSdkVersion', version); }) console.log('[joinChannel] ' + this.props.channelName); RtcEngine.joinChannel(this.props.channelName, this.props.uid); RtcEngine.enableAudioVolumeIndication(500, 3); } componentWillUnmount () { if (this.state.joinSucceed) { RtcEngine.leaveChannel(); RtcEngine.removeAllListeners(); RtcEngine.destroy(); } } handleCancel = () => { RtcEngine.leaveChannel(); RtcEngine.removeAllListeners(); RtcEngine.destroy(); this.props.onCancel(); } switchCamera = () => { RtcEngine.switchCamera(); } toggleAllRemoteAudioStreams = () => { this.setState({ isMute: !this.state.isMute }, () => { RtcEngine.muteAllRemoteAudioStreams(this.state.isMute); }) } toggleSpeakerPhone = () => { this.setState({ isSpeak: !this.state.isSpeak }, () => { RtcEngine.setDefaultAudioRouteToSpeakerphone(this.state.isSpeak); }) } toggleCameraTorch = () => { this.setState({ isCameraTorch: !this.state.isCameraTorch }, () => { RtcEngine.setCameraTorchOn(this.state.isCameraTorch).then(val => { console.log("setCameraTorch", val); }) }) } toggleVideo = () => { this.setState({ disableVideo: !this.state.videodisableVideo }, () => { this.state.disableVideo ? RtcEngine.enableVideo() : RtcEngine.disableVideo() }); } toggleHideButtons = () => { this.setState({ hideButton: !this.state.hideButton }) } onPressVideo = (uid) => { this.setState({ selectedUid: uid }, () => { this.setState({ visible: true }) }) } buttonsView = ({hideButton, isCameraTorch, disableVideo, isMute, isSpeaker}) => { if (!hideButton) { return ( ) } } agoraPeerViews = ({visible, peerIds}) => { return (visible ? : { peerIds.map((uid, key) => ( this.onPressVideo(uid)} key={key}> )) }) } modalView = ({visible}) => { return ( {}} > this.setState({ visible: false })} > ) } render () { if (!this.state.joinSucceed) { return ( Creating a video conference... ) } return ( channelName: {this.props.channelName}, peers: {this.state.peerIds.length} {this.agoraPeerViews(this.state)} {this.buttonsView(this.state)} {this.modalView(this.state)} ) } }