import React, { Component } from 'react'; import { Platform, TextInput, ScrollView, Button, Alert, Linking, StyleSheet, Text, View, Image, PermissionsAndroid } from 'react-native'; import InCallManager from 'react-native-incall-manager'; import axios from 'axios'; import { OpenViduReactNativeAdapter, OpenVidu, RTCView } from 'openvidu-react-native-adapter'; const OPENVIDU_SERVER_URL = 'https://demos.openvidu.io'; const OPENVIDU_SERVER_SECRET = 'MY_SECRET'; type Props = {}; export default class App extends Component { constructor(props) { super(props); const ovReact = new OpenViduReactNativeAdapter(); ovReact.initialize(); this.state = { mySessionId: 'testReact', myUserName: 'Participant' + Math.floor(Math.random() * 100), session: undefined, mainStreamManager: undefined, subscribers: [], role: 'PUBLISHER', mirror: true, videoSource: undefined, video: true, audio: true, speaker: false, joinBtnEnabled: true, isReconnecting: false, }; } componentDidMount() { //this.joinSession(); } // componentWillUnmount() { // this.leaveSession(); // } async checkAndroidPermissions() { try { const camera = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA, { title: 'Camera Permission', message: 'OpenVidu needs access to your camera', buttonNeutral: 'Ask Me Later', buttonNegative: 'Cancel', buttonPositive: 'OK', }); const audio = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, { title: 'Audio Permission', message: 'OpenVidu needs access to your microphone', buttonNeutral: 'Ask Me Later', buttonNegative: 'Cancel', buttonPositive: 'OK', }); const storage = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, { title: 'STORAGE', message: 'OpenVidu needs access to your storage ', buttonNeutral: 'Ask Me Later', buttonNegative: 'Cancel', buttonPositive: 'OK', }); if (camera === PermissionsAndroid.RESULTS.GRANTED) { console.log('You can use the camera'); } else { console.log('Camera permission denied'); } if (audio === PermissionsAndroid.RESULTS.GRANTED) { console.log('You can use the audio'); } else { console.log('audio permission denied'); } if (storage === PermissionsAndroid.RESULTS.GRANTED) { console.log('You can use the storage'); } else { console.log('storage permission denied'); } } catch (err) { console.warn(err); } } joinSession() { // --- 1) Get an OpenVidu object --- this.OV = new OpenVidu(); this.OV.enableProdMode(); // --- 2) Init a session --- this.setState( { joinBtnEnabled: false, session: this.OV.initSession(), }, async () => { const mySession = this.state.session; // --- 3) Specify the actions when events take place in the session --- // On every new Stream received... mySession.on('streamCreated', async (event) => { // Subscribe to the Stream to receive it. Second parameter is undefined // so OpenVidu doesn't create an HTML video by its own const subscriber = await mySession.subscribeAsync(event.stream, undefined); var subscribers = Array.from(this.state.subscribers); subscribers.push(subscriber); // Update the state with the new subscribers this.setState({ subscribers: subscribers, }); }); // On every Stream destroyed... mySession.on('streamDestroyed', (event) => { event.preventDefault(); // Remove the stream from 'subscribers' array this.deleteSubscriber(event.stream); }); // On every asynchronous exception... mySession.on('exception', (exception) => { console.warn(exception); }); // On reconnection events mySession.on('reconnecting', () => { console.warn('Oops! Trying to reconnect to the session'); this.setState({ isReconnecting: true }); }); mySession.on('reconnected', () => { console.log('Hurray! You successfully reconnected to the session'); setTimeout(() => { // Force re-render view updating state avoiding frozen streams this.setState({ isReconnecting: false }); }, 2000); }); mySession.on('sessionDisconnected', (event) => { if (event.reason === 'networkDisconnect') { console.warn('Dang-it... You lost your connection to the session'); this.leaveSession(); } else { // Disconnected from the session for other reason than a network drop } }); try { // --- 4) Connect to the session with a valid user token --- // 'getToken' method is simulating what your server-side should do. // 'token' parameter should be retrieved and returned by your own backend const token = await this.getToken(); // First param is the token got from OpenVidu Server. Second param can be retrieved by every user on event // 'streamCreated' (property Stream.connection.data), and will be appended to DOM as the user's nickname await mySession.connect(token, { clientData: this.state.myUserName }); if (Platform.OS === 'android') { await this.checkAndroidPermissions(); } // --- 5) Get your own camera stream --- if (this.state.role !== 'SUBSCRIBER') { const properties = { audioSource: undefined, // The source of audio. If undefined default microphone videoSource: undefined, // The source of video. If undefined default webcam publishAudio: true, // Whether you want to start publishing with your audio unmuted or not publishVideo: true, // Whether you want to start publishing with your video enabled or not resolution: '640x480', // The resolution of your video frameRate: 30, // The frame rate of your video insertMode: 'APPEND', // How the video is inserted in the target element 'video-container' }; // Init a publisher passing undefined as targetElement (we don't want OpenVidu to insert a video // element: we will manage it on our own) and with the desired propertiesç const publisher = await this.OV.initPublisherAsync(undefined, properties); // --- 6) Publish your stream --- // Set the main video in the page to display our webcam and store our Publisher this.setState( { mainStreamManager: publisher, videoSource: !properties.videoSource ? '1' : properties.videoSource, // 0: back camera | 1: user camera | }, () => { mySession.publish(publisher); }, ); } } catch (error) { console.log('There was an error connecting to the session:', error.code, error.message); this.setState({ joinBtnEnabled: true, }); } }, ); } getNicknameTag(stream) { // Gets the nickName of the user try { if (stream.connection && JSON.parse(stream.connection.data) && JSON.parse(stream.connection.data).clientData) { return JSON.parse(stream.connection.data).clientData; } } catch (error) {} return ''; } deleteSubscriber(stream) { var subscribers = Array.from(this.state.subscribers); const index = subscribers.indexOf(stream.streamManager, 0); if (index > -1) { subscribers.splice(index, 1); this.setState({ subscribers: subscribers, }); } } leaveSession() { // --- 7) Leave the session by calling 'disconnect' method over the Session object --- const mySession = this.state.session; if (mySession) { mySession.disconnect(); } // Empty all properties... setTimeout(() => { this.OV = null; this.setState({ session: undefined, subscribers: [], mySessionId: 'testReact', myUserName: 'Participant' + Math.floor(Math.random() * 100), mainStreamManager: undefined, publisher: undefined, joinBtnEnabled: true, }); }); } toggleCamera() { /** * _switchCamera() Method provided by react-native-webrtc: * This function allows to switch the front / back cameras in a video track on the fly, without the need for adding / removing tracks or renegotiating */ const camera = this.state.mainStreamManager.stream.getMediaStream().getVideoTracks()[0]; if (camera) { camera._switchCamera(); this.setState({ mirror: !this.state.mirror }); } /** * Traditional way: * Renegotiating stream and init new publisher to change the camera */ /* this.OV.getDevices().then(devices => { console.log("DEVICES => ", devices); let device = devices.filter(device => device.kind === 'videoinput' && device.deviceId !== this.state.videoSource)[0] const properties = { audioSource: undefined, videoSource: device.deviceId, publishAudio: true, publishVideo: true, resolution: '640x480', frameRate: 30, insertMode: 'APPEND', } let publisher = this.OV.initPublisher(undefined, properties); this.state.session.unpublish(this.state.mainStreamManager); this.setState({ videoSource : device.deviceId, mainStreamManager: publisher, mirror: !this.state.mirror }); this.state.session.publish(publisher); }); */ } muteUnmuteMic() { this.state.mainStreamManager.publishAudio(!this.state.audio); this.setState({ audio: !this.state.audio }); } muteUnmuteCamera() { this.state.mainStreamManager.publishVideo(!this.state.video); this.setState({ video: !this.state.video }); } muteUnmuteSpeaker() { InCallManager.setSpeakerphoneOn(!this.state.speaker); this.setState({ speaker: !this.state.speaker }); } render() { return ( {this.state.mainStreamManager && this.state.mainStreamManager.stream ? ( Session: {this.state.mySessionId} {this.getNicknameTag(this.state.mainStreamManager.stream)}