No Description

agora.js 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. import React, {Component, PureComponent} from 'react';
  2. import {
  3. StyleSheet, Text, View, TouchableOpacity,
  4. Image, Dimensions, Modal
  5. } from 'react-native';
  6. import {RtcEngine, AgoraView} from 'react-native-agora';
  7. import {
  8. APPID,
  9. } from '../utils';
  10. const BtnEndCall = () => require('../assets/btn_endcall.png');
  11. const BtnMute = () => require('../assets/btn_mute.png');
  12. const BtnSpeaker = () => require('../assets/btn_speaker.png');
  13. const BtnSwitchCamera = () => require('../assets/btn_switch_camera.png');
  14. const BtnVideo = () => require('../assets/btn_video.png');
  15. const EnableCamera = () => require('../assets/enable_camera.png');
  16. const DisableCamera = () => require('../assets/disable_camera.png');
  17. const EnablePhotoflash = () => require('../assets/enable_photoflash.png');
  18. const DisablePhotoflash = () => require('../assets/disable_photoflash.png');
  19. const IconMuted = () => require('../assets/icon_muted.png');
  20. const IconSpeaker = () =>require('../assets/icon_speaker.png');
  21. const {width} = Dimensions.get('window');
  22. const styles = StyleSheet.create({
  23. container: {
  24. flex: 1,
  25. backgroundColor: '#F4F4F4'
  26. },
  27. absView: {
  28. position: 'absolute',
  29. top: 20,
  30. left: 0,
  31. right: 0,
  32. bottom: 0,
  33. justifyContent: 'space-between',
  34. },
  35. videoView: {
  36. padding: 5,
  37. flexWrap: 'wrap',
  38. flexDirection: 'row',
  39. zIndex: 100
  40. },
  41. localView: {
  42. flex: 1
  43. },
  44. remoteView: {
  45. width: (width - 40) / 3,
  46. height: (width - 40) / 3,
  47. margin: 5
  48. },
  49. bottomView: {
  50. padding: 20,
  51. flexDirection: 'row',
  52. justifyContent: 'space-around'
  53. }
  54. });
  55. class OperateButton extends PureComponent {
  56. render() {
  57. const {onPress, source, style, imgStyle = {width: 50, height: 50}} = this.props;
  58. return (
  59. <TouchableOpacity
  60. style={style}
  61. onPress={onPress}
  62. activeOpacity={.7}
  63. >
  64. <Image
  65. style={imgStyle}
  66. source={source}
  67. />
  68. </TouchableOpacity>
  69. )
  70. }
  71. }
  72. type Props = {
  73. channelProfile: Number,
  74. videoProfile: Number,
  75. clientRole: Number,
  76. swapWidthAndHeight: Boolean,
  77. onCancel: Function
  78. }
  79. export default class Agora extends Component<Props> {
  80. state = {
  81. peerIds: [],
  82. joinSucceed: false,
  83. isSpeak: true,
  84. isMute: false,
  85. isCameraTorch: false,
  86. disableVideo: false,
  87. hideButton: false,
  88. visible: false,
  89. selectedUid: undefined,
  90. };
  91. componentWillMount () {
  92. const config = {
  93. appid: APPID,
  94. channelProfile: this.props.channelProfile,
  95. videoProfile: this.props.videoProfile,
  96. clientRole: this.props.clientRole,
  97. swapWidthAndHeight: this.props.swapWidthAndHeight
  98. }
  99. console.log("[CONFIG]", config);
  100. RtcEngine.init(config);
  101. }
  102. componentDidMount () {
  103. RtcEngine.getSdkVersion((version) => {
  104. console.log('[RtcEngine] getSdkVersion', version);
  105. })
  106. RtcEngine.joinChannel();
  107. RtcEngine.enableAudioVolumeIndication(500, 3);
  108. RtcEngine.eventEmitter({
  109. onFirstRemoteVideoDecoded: (data) => {
  110. console.log('[RtcEngine] onFirstRemoteVideoDecoded', data);
  111. const {peerIds} = this.state;
  112. if (peerIds.indexOf(data.uid) !== -1) {
  113. this.setState({
  114. peerIds: [...peerIds, data.uid]
  115. })
  116. }
  117. },
  118. onUserOffline: (data) => {
  119. console.log('[RtcEngine] onUserOffline', data);
  120. this.setState({
  121. peerIds: this.state.peerIds.filter(uid => uid !== data.uid)
  122. })
  123. },
  124. onJoinChannelSuccess: (data) => {
  125. console.log('[RtcEngine] onJoinChannelSuccess', data);
  126. // RtcEngine.setShowLocalVideo()
  127. RtcEngine.startPreview();
  128. this.setState({
  129. joinSucceed: true
  130. })
  131. },
  132. onAudioVolumeIndication: (data) => {
  133. console.log('[RtcEngine] onAudioVolumeIndication', data);
  134. },
  135. onUserJoined: (data) => {
  136. console.log('[RtcEngine] onUserJoined', data);
  137. },
  138. onError: (data) => {
  139. console.log('[RtcEngine] onError', data);
  140. if (data.error === 17) {
  141. RtcEngine.leaveChannel();
  142. RtcEngine.destroy();
  143. }
  144. this.props.onCancel(data.error);
  145. }
  146. })
  147. }
  148. componentWillUnmount () {
  149. RtcEngine.removeEmitter()
  150. }
  151. handleCancel = () => {
  152. RtcEngine.leaveChannel();
  153. RtcEngine.destroy();
  154. this.props.onCancel();
  155. }
  156. switchCamera = () => {
  157. RtcEngine.switchCamera();
  158. }
  159. toggleAllRemoteAudioStreams = () => {
  160. this.setState({
  161. isMute: !this.state.isMute
  162. }, () => {
  163. RtcEngine.muteAllRemoteAudioStreams(this.state.isMute);
  164. })
  165. }
  166. toggleSpeakerPhone = () => {
  167. this.setState({
  168. isSpeak: !this.state.isSpeak
  169. }, () => {
  170. RtcEngine.setDefaultAudioRouteToSpeakerphone(this.state.isSpeak);
  171. })
  172. }
  173. toggleCameraTorch = () => {
  174. this.setState({
  175. isCameraTorch: !this.state.isCameraTorch
  176. }, () => {
  177. RtcEngine.setCameraTorchOn(this.state.isCameraTorch)
  178. })
  179. }
  180. toggleVideo = () => {
  181. this.setState({
  182. disableVideo: !this.state.videodisableVideo
  183. }, () => {
  184. this.state.disableVideo ? RtcEngine.enableVideo() : RtcEngine.disableVideo()
  185. });
  186. }
  187. toggleHideButtons = () => {
  188. this.setState({
  189. hideButton: !this.state.hideButton
  190. })
  191. }
  192. onPressVideo = (uid) => {
  193. this.setState({
  194. selectedUid: uid
  195. }, () => {
  196. this.setState({
  197. visible: true
  198. })
  199. })
  200. }
  201. buttonsView = ({hideButton, isCameraTorch, disableVideo, isMute, isSpeaker}) => {
  202. if (!hideButton) {
  203. return (
  204. <View>
  205. <OperateButton
  206. style={{alignSelf: 'center', marginBottom: -10}}
  207. onPress={this.handleCancel}
  208. imgStyle={{width: 60, height: 60}}
  209. source={BtnEndCall()}
  210. />
  211. <View style={styles.bottomView}>
  212. <OperateButton
  213. onPress={this.toggleCameraTorch}
  214. imgStyle={{width: 40, height: 40}}
  215. source={isCameraTorch ? EnablePhotoflash() : DisablePhotoflash()}
  216. />
  217. <OperateButton
  218. onPress={this.toggleVideo}
  219. source={disableVideo ? EnableCamera() : DisableCamera()}
  220. />
  221. </View>
  222. <View style={styles.bottomView}>
  223. <OperateButton
  224. onPress={this.toggleAllRemoteAudioStreams}
  225. source={isMute ? IconMuted() : BtnMute()}
  226. />
  227. <OperateButton
  228. onPress={this.switchCamera}
  229. source={BtnSwitchCamera()}
  230. />
  231. <OperateButton
  232. onPress={this.toggleSpeakerPhone}
  233. source={!isSpeaker ? IconSpeaker() : BtnSpeaker()}
  234. />
  235. </View>
  236. </View>)
  237. }
  238. }
  239. agoraPeerViews = ({visible, peerIds}) => {
  240. return (visible ?
  241. <View style={styles.videoView} /> :
  242. <View style={styles.videoView}>{
  243. peerIds.map((uid, key) => (
  244. <TouchableOpacity
  245. activeOpacity={1}
  246. onPress={() => this.onPressVideo(uid)}
  247. key={key}>
  248. <AgoraView
  249. style={styles.remoteView}
  250. zOrderMediaOverlay={true}
  251. remoteUid={uid}
  252. />
  253. </TouchableOpacity>
  254. ))
  255. }</View>)
  256. }
  257. modalView = ({visible}) => {
  258. return (
  259. <Modal
  260. visible={visible}
  261. presentationStyle={'fullScreen'}
  262. animationType={'slide'}
  263. onRequestClose={() => {}}
  264. >
  265. <TouchableOpacity
  266. activeOpacity={1}
  267. style={{flex: 1}}
  268. onPress={() => this.setState({
  269. visible: false
  270. })} >
  271. <AgoraView
  272. style={{flex: 1}}
  273. zOrderMediaOverlay={true}
  274. remoteUid={this.state.selectedUid}
  275. />
  276. </TouchableOpacity>
  277. </Modal>)
  278. }
  279. render () {
  280. if (!this.state.joinSucceed) {
  281. return (
  282. <View style={{flex: 1, backgroundColor: '#fff', justifyContent: 'center', alignItems: 'center'}}>
  283. <Text>Creating a video conference...</Text>
  284. </View>
  285. )
  286. }
  287. return (
  288. <TouchableOpacity
  289. activeOpacity={1}
  290. onPress={this.toggleHideButtons}
  291. style={styles.container}
  292. >
  293. <AgoraView style={styles.localView} showLocalVideo={true} />
  294. <View style={styles.absView}>
  295. {this.agoraPeerViews(this.state)}
  296. {this.buttonsView(this.state)}
  297. </View>
  298. {this.modalView(this.state)}
  299. </TouchableOpacity>
  300. )
  301. }
  302. }