Hello, everything works very smoothly.
I can video call for testing with a device without any problems.
Image cannot be transferred when I try with another device. What could be the problem?
`import React, {Component} from ‘react’;
import {
SafeAreaView,
View,
Text,
Image,
TouchableOpacity,
StyleSheet,
Dimensions,
ActivityIndicator, TouchableHighlight
} from ‘react-native’;
import Icon from ‘react-native-vector-icons/FontAwesome5’;
import {
mediaDevices,
RTCPeerConnection,
RTCSessionDescription,
RTCView,
RTCIceCandidate,
} from ‘react-native-webrtc’;
import {withSocketContext} from “…/…/…/config/create-context-socket”;
import {inject} from “mobx-react”;
const screenHeight =Math.round(Dimensions.get(‘window’).height);
const screenWidth = Math.round(Dimensions.get(‘window’).width);
@Inject(‘AuthStore’)
class VideoCall extends Component<any, any> {
configuration: any = {iceServers: [{url: ‘stun:stun.l.google.com:19302’}]};
state: any = {
localStream: ‘’,
remoteStream: ‘’,
to: ‘’,
from: ‘’,
type: ‘’,
isFinish: false,
isMuted:false,
};
socket = this.props.socket;
peer = new RTCPeerConnection(this.configuration);
startLocalStream = async () => {
// isFront will determine if the initial camera should face user or environment
const isFront = true;
const devices = await mediaDevices.enumerateDevices();
const facing = isFront ? 'front' : 'environment';
const videoSourceId = devices.find(
device => device.kind === 'videoinput' && device.facing === facing,
);
const facingMode = isFront ? 'user' : 'environment';
const constraints: any = {
audio: true,
video: {
mandatory: {
minWidth: 500, // Provide your own width, height and frame rate here
minHeight: 300,
minFrameRate: 30,
},
facingMode,
optional: videoSourceId ? [{sourceId: videoSourceId}] : [],
},
};
const newStream = await mediaDevices.getUserMedia(constraints);
this.setState({
localStream: newStream,
});
this.peer.addStream(newStream);
};
createAndSendOffer = async () => {
const offer = await this.peer.createOffer();
const sd = new RTCSessionDescription(offer);
this.peer.setLocalDescription(sd);
// send offer infi via socket.io
this.socket.emit(
'call_test',
this.state.to,
JSON.stringify({sdp: sd}),
);
};
createAndSendAnswer = async () => {
const {from} = this.state;
const answer = await this.peer.createAnswer();
const ans = new RTCSessionDescription(answer);
await this.peer.setLocalDescription(ans);
if (ans) {
this.socket.emit('call_test', from, JSON.stringify({sdp: ans}));
}
// wsc.send(JSON.stringify({ sdp: ans }));
};
initCall = async () => {
// send any ice candidates to the other peer
this.peer.onicecandidate = this.onIceCandidateHandler;
// once remote stream arrives, show it in the remote video element
this.peer.onaddstream = this.onAddStreamHandler;
};
onIceCandidateHandler = evt => {
if (!evt || !evt.candidate) return;
//Send Candidadte
if (this.state.from) {
this.socket.emit(
'call_test',
this.state.from,
JSON.stringify({candidate: evt.candidate}),
);
} else {
this.socket.emit(
'call_test',
this.state.to,
JSON.stringify({candidate: evt.candidate}),
);
}
// wsc.send(JSON.stringify({candidate: evt.candidate}));
};
onAddStreamHandler = evt => {
// videoCallButton.setAttribute('disabled', true);
// endCallButton.removeAttribute('disabled');
// set remote video stream as source for remote video HTML5 element
this.setState({
remoteStream: evt.stream,
});
};
dispose = () => {
this.peer.close();
this.peer.removeStream(this.state.localStream);
this.setState({localStream: ''});
this.props.navigation.goBack();
};
sendDismiss = isOffer => {
this.socket.emit(
'call_test',
(this.props.AuthStore.token == this.state.from) ? this.state.to : this.state.from,
'dismiss',
);
this.dispose();
};
async componentDidMount() {
await this.initCall();
await this.startLocalStream();
const to = this.props.navigation.getParam('to', '');
const from = this.props.navigation.getParam('from', '');
const type = this.props.navigation.getParam('type', 'ingoing');
console.log('Arayan ',from);
console.log('Alıcı',to);
//if (type === 'outgoing') {
this.setState({
to: to,
from: from,
type: type,
});
//}
this.socket.on('call_test', async (to, evt) => {
if (evt === 'dismiss') {
this.dispose();
return;
}
if (evt === 'ready') {
await this.createAndSendOffer();
setTimeout(async () => {
this.socket.emit(
'call_test',
this.state.to,
'calling me',
);
this.setState({
isFinish: true,
});
}, 1000);
}
let signal: any = null;
if (evt !== 'calling me' && evt !== 'ready') {
signal = JSON.parse(evt);
}
console.log(signal)
if (signal && signal.hasOwnProperty('sdp') && signal.sdp) {
this.peer.setRemoteDescription(new RTCSessionDescription(signal.sdp));
} else if (signal && signal.candidate) {
this.peer.addIceCandidate(new RTCIceCandidate(signal.candidate));
} else if (signal && signal.closeConnection) {
} else if (evt === 'calling me') {
this.createAndSendAnswer();
}
});
if (!this.state.isFinish && this.state.type === 'outgoing') {
this.readyConversation();
}
}
componentWillUnmount() {
const {from} = this.state;
this.dispose();
this.sendDismiss(from ? false : true);
}
readyConversation = () => {
this.socket.emit('call_test', this.state.from, 'ready');
this.setState({
isFinish: true,
});
};
switchCamera = async () => {
this.state.localStream.getVideoTracks().forEach(track => track._switchCamera());
};
toggleMute = () => {
if (!this.remoteStream) return;
this.state.localStream.getAudioTracks().forEach(track => {
track.enabled = !track.enabled;
this.setState({
isMuted:!track.enabled
})
});
};
render() {
const {isFinish} = this.state;
return (
<SafeAreaView style={styles.root}>
<TouchableOpacity onPress={this.switchCamera} style={styles.changeCamera} >
<Image style={{ width:60,height:60}} source={require('../../../../assets/image/app/turn-camera.png') } />
</TouchableOpacity>
<RTCView streamURL={this.state.remoteStream && this.state.remoteStream.toURL()} style={styles.localVideo} mirror={true} />
<RTCView streamURL={this.state.localStream && this.state.localStream.toURL()} mirror={true} style={styles.remoteVideo} />
{!this.state.isFinish &&
<View style={styles.loading}>
<ActivityIndicator size={30} color={"white"}/>
<Text style={{color: 'white', fontSize: 14, marginLeft: 15, fontFamily: 'Rubik-Bold'}}>Bağlanıyor,
Lütfen bekleyiniz...</Text>
</View>
}
<View style={styles.buttonContainer}>
<TouchableHighlight style={[styles.button2, styles.microphoneButton]} onPress={() => this.toggleMute()}>
<Icon name={(this.state.isMuted) ? 'microphone-alt-slash' : 'microphone-alt' } size={20} color={'white'}/>
</TouchableHighlight>
<TouchableHighlight style={[styles.button, styles.buttonCall]} onPress={() => this.sendDismiss()}>
<Icon name={"phone-slash"} size={20} color={"white"} />
</TouchableHighlight>
</View>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
root: {
flex: 1,
},
changeCamera:{
top: 30,
right: 10,
position: "absolute",
zIndex:2,
elevation:2,
},
localVideo: {
width: '100%',
height: '100%',
backgroundColor:"black",
},
remoteVideo: {
top: 30,
left: 30,
width: 114,
height: 170,
backgroundColor: "rgba(230, 230, 230,1)",
position: "absolute",
zIndex:999,
elevation:999,
},
buttonContainer:{
top:screenHeight - 140,
position:'absolute',
alignSelf: 'center',
flexDirection:'row',
justifyContent:'center',
marginTop:20,
alignItems:'center',
},
button: {
width:60,
height:60,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
marginBottom:20,
borderRadius:30,
margin:10,
shadowColor: 'black',
shadowOpacity: .8,
shadowOffset: {
height:2,
width:-2
},
elevation:4,
},
button2: {
width:40,
height:40,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
marginBottom:20,
borderRadius:30,
margin:10,
shadowColor: 'black',
shadowOpacity: .8,
shadowOffset: {
height:2,
width:-2
},
elevation:4,
},
buttonCall: {
backgroundColor: "red",
},
microphoneButton: {
backgroundColor: "rgba(255,255,255,0.4)",
},
icon: {
width:35,
height:35,
}
,
loading:{
flexDirection:'row',
justifyContent:'center',
alignItems:'center',
backgroundColor: "rgba(0, 0, 0,100.7)",
position:'absolute',
top:'50%',
width:'90%',
alignSelf: 'center',
height:50,
}
});
export default withSocketContext(VideoCall);
`