|
|
|
@ -8,11 +8,10 @@ import {
|
|
|
|
|
Text, |
|
|
|
|
TouchableOpacity, |
|
|
|
|
StyleSheet, |
|
|
|
|
DeviceEventEmitter, |
|
|
|
|
TextInput, |
|
|
|
|
} from 'react-native'; |
|
|
|
|
import * as Animatable from 'react-native-animatable'; |
|
|
|
|
import TextInputContainer from './components/TextInputContainer'; |
|
|
|
|
import SocketIOClient from 'socket.io-client'; |
|
|
|
|
import { |
|
|
|
|
mediaDevices, |
|
|
|
|
RTCPeerConnection, |
|
|
|
@ -32,52 +31,74 @@ import IconContainer from './components/IconContainer';
|
|
|
|
|
import InCallManager from 'react-native-incall-manager'; |
|
|
|
|
import Logo from './asset/Logo'; |
|
|
|
|
import * as JsSIP from 'react-native-jssip'; |
|
|
|
|
import EventEmitter from 'react-native/Libraries/vendor/emitter/EventEmitter'; |
|
|
|
|
|
|
|
|
|
export default function App({}) { |
|
|
|
|
const eventoSip = new EventEmitter(); |
|
|
|
|
const [session, setSession] = useState(null); |
|
|
|
|
const [ua, setUa] = useState(null); |
|
|
|
|
const [screen, setScreen] = useState('JOIN'); |
|
|
|
|
const [incomingCaller, setIncomingCaller] = useState(null); |
|
|
|
|
const [calle, setCalle] = useState(null); |
|
|
|
|
const [myRamal, setMyRamal] = useState(null); |
|
|
|
|
const [authData, setAuthData] = useState({ |
|
|
|
|
protocolo: 'ws', |
|
|
|
|
servidor: '192.168.115.179', |
|
|
|
|
porta: '8088', |
|
|
|
|
username: 'Matheo', |
|
|
|
|
ramal: '1100', |
|
|
|
|
senha: 'SIP1100', |
|
|
|
|
}); |
|
|
|
|
const [localMicOn, setlocalMicOn] = useState(true); |
|
|
|
|
const [localWebcamOn, setlocalWebcamOn] = useState(false); |
|
|
|
|
const [localStream, setLocalStream] = useState(null); |
|
|
|
|
const [remoteStream, setRemoteStream] = useState(null); |
|
|
|
|
const remoteAudio = useRef(null); |
|
|
|
|
const localAudio = useRef(null); |
|
|
|
|
|
|
|
|
|
function Autenticacao(PROTOCOLO, SERVIDOR, PORTA, NOME, RAMAL, SENHA) { |
|
|
|
|
this.PROTOCOLO = 'ws'; |
|
|
|
|
this.SERVIDOR = '192.168.115.179'; |
|
|
|
|
this.PORTA = '8088'; |
|
|
|
|
this.NOME = 'matheo'; |
|
|
|
|
this.RAMAL = '1100'; |
|
|
|
|
this.SENHA = 'SIP1100'; |
|
|
|
|
class EventEmitter { |
|
|
|
|
constructor() { |
|
|
|
|
this.events = {}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
on(eventName, listener) { |
|
|
|
|
if (!this.events[eventName]) { |
|
|
|
|
this.events[eventName] = []; |
|
|
|
|
} |
|
|
|
|
this.events[eventName].push(listener); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const _Autenticacao = new Autenticacao(); |
|
|
|
|
emit(eventName, ...args) { |
|
|
|
|
if (this.events[eventName]) { |
|
|
|
|
this.events[eventName].forEach(listener => listener(...args)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let phone; |
|
|
|
|
let session; |
|
|
|
|
off(eventName, listener) { |
|
|
|
|
if (this.events[eventName]) { |
|
|
|
|
this.events[eventName] = this.events[eventName].filter( |
|
|
|
|
fn => fn !== listener, |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
const eventoSip = new EventEmitter(); |
|
|
|
|
const {protocolo, servidor, porta, username, ramal, senha} = authData; |
|
|
|
|
|
|
|
|
|
function iniciandoAutenticacaonoPBX() { |
|
|
|
|
useEffect(() => { |
|
|
|
|
setMyRamal(ramal); |
|
|
|
|
const socket = new JsSIP.WebSocketInterface( |
|
|
|
|
_Autenticacao.PROTOCOLO + |
|
|
|
|
'://' + |
|
|
|
|
_Autenticacao.SERVIDOR + |
|
|
|
|
':' + |
|
|
|
|
_Autenticacao.PORTA + |
|
|
|
|
'/ws', |
|
|
|
|
protocolo + '://' + servidor + ':' + porta + '/ws', |
|
|
|
|
); |
|
|
|
|
const configuration = { |
|
|
|
|
uri: 'sip:' + _Autenticacao.RAMAL + '@' + _Autenticacao.SERVIDOR, |
|
|
|
|
password: _Autenticacao.SENHA, |
|
|
|
|
uri: 'sip:' + ramal + '@' + servidor, |
|
|
|
|
password: senha, |
|
|
|
|
sockets: [socket], |
|
|
|
|
session_timers: false, |
|
|
|
|
no_answer_timeout: 180, |
|
|
|
|
hack_via_tcp: false, |
|
|
|
|
hack_via_ws: true, |
|
|
|
|
display_name: |
|
|
|
|
_Autenticacao.NOME !== null ? _Autenticacao.NOME : _Autenticacao.RAMAL, |
|
|
|
|
user_agent: 'UASimpleSIP 1.2.0', |
|
|
|
|
contact_uri: |
|
|
|
|
'sip:' + |
|
|
|
|
_Autenticacao.RAMAL + |
|
|
|
|
'@' + |
|
|
|
|
_Autenticacao.SERVIDOR + |
|
|
|
|
';transport=' + |
|
|
|
|
_Autenticacao.PROTOCOLO, |
|
|
|
|
display_name: username !== null ? username : ramal, |
|
|
|
|
user_agent: 'Softphone React Native', |
|
|
|
|
contact_uri: 'sip:' + ramal + '@' + servidor + ';transport=' + protocolo, |
|
|
|
|
pcConfig: { |
|
|
|
|
iceServers: [ |
|
|
|
|
{ |
|
|
|
@ -92,8 +113,8 @@ export default function App({}) {
|
|
|
|
|
], |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
if (configuration.uri && configuration.password) { |
|
|
|
|
phone = new JsSIP.UA(configuration); |
|
|
|
|
|
|
|
|
|
const phone = new JsSIP.UA(configuration); |
|
|
|
|
|
|
|
|
|
phone.on('registrationFailed', function (ev) { |
|
|
|
|
console.log('Registering on SIP server failed with error: ' + ev.cause); |
|
|
|
@ -101,21 +122,10 @@ export default function App({}) {
|
|
|
|
|
configuration.password = null; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
phone.on('newRTCSession', function (ev) { |
|
|
|
|
phone.on('newRTCSession', ev => { |
|
|
|
|
const newSession = ev.session; |
|
|
|
|
|
|
|
|
|
session = newSession; |
|
|
|
|
|
|
|
|
|
eventoSip.on('endCall', () => { |
|
|
|
|
if (session) { |
|
|
|
|
eventoSip.emit('confirmedEnded'); |
|
|
|
|
session.terminate(); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
eventoSip.on('evento', payload => { |
|
|
|
|
console.log(payload); |
|
|
|
|
}); |
|
|
|
|
///////////////////////////////////////////////////
|
|
|
|
|
eventoSip.on('mute', () => { |
|
|
|
|
session.mute(); |
|
|
|
|
console.log(session?.isMuted()); |
|
|
|
@ -133,54 +143,82 @@ export default function App({}) {
|
|
|
|
|
eventoSip.on('transferir', data => { |
|
|
|
|
session.refer(data); |
|
|
|
|
}); |
|
|
|
|
///////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
//RECEBENDO UMA CHAMADA
|
|
|
|
|
if (newSession.direction === 'incoming') { |
|
|
|
|
setScreen('INCOMING_CALL'); |
|
|
|
|
setIncomingCaller(newSession.remote_identity.uri.user); |
|
|
|
|
setSession(newSession); |
|
|
|
|
// Set InCallManager settings when a call starts
|
|
|
|
|
InCallManager.start({media: 'audio'}); |
|
|
|
|
InCallManager.setForceSpeakerphoneOn(true); |
|
|
|
|
|
|
|
|
|
session.on('candidate', event => { |
|
|
|
|
console.log(event); |
|
|
|
|
//Quando finalizar a chamada
|
|
|
|
|
newSession.on('ended', () => { |
|
|
|
|
InCallManager.stop(); |
|
|
|
|
setSession(null); |
|
|
|
|
setIncomingCaller(null); |
|
|
|
|
setScreen('JOIN'); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
session.on('ended', () => { |
|
|
|
|
endCallAudio.play(); |
|
|
|
|
eventoSip.emit('confirmedEnded'); |
|
|
|
|
//QUANDO UMA CHAMADA APRESENTAR PROBLEMAS
|
|
|
|
|
newSession.on('failed', () => { |
|
|
|
|
InCallManager.stop(); |
|
|
|
|
setSession(null); |
|
|
|
|
setIncomingCaller(null); |
|
|
|
|
setScreen('JOIN'); |
|
|
|
|
}); |
|
|
|
|
} else { |
|
|
|
|
setSession(newSession); |
|
|
|
|
|
|
|
|
|
session.on('newDTMF', function (event) { |
|
|
|
|
console.log('DTMF recebido:', event.dtmf.tone); |
|
|
|
|
//Quando finalizar a chamada
|
|
|
|
|
newSession.on('ended', () => { |
|
|
|
|
InCallManager.stop(); |
|
|
|
|
setSession(null); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
//QUANDO UMA CHAMADA Ã REJEITADA
|
|
|
|
|
session.on('failed', () => { |
|
|
|
|
incomingCallAudio.pause(); |
|
|
|
|
outgoingCallAudio.pause(); |
|
|
|
|
eventoSip.emit('home'); |
|
|
|
|
//QUANDO UMA CHAMADA APRESENTAR PROBLEMAS
|
|
|
|
|
newSession.on('failed', () => { |
|
|
|
|
InCallManager.stop(); |
|
|
|
|
setSession(null); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
session.on('confirmed', function (confirmed) { |
|
|
|
|
// Verifica se session.connection está definido
|
|
|
|
|
if ( |
|
|
|
|
session.connection && |
|
|
|
|
session.connection.getRemoteStreams().length > 0 |
|
|
|
|
) { |
|
|
|
|
const remoteStreams = session.connection.getRemoteStreams()[0]; |
|
|
|
|
remoteAudio.srcObject = remoteStreams; |
|
|
|
|
remoteAudio.volume = 1; |
|
|
|
|
newSession.on('peerconnection', e => { |
|
|
|
|
const peerconnection = e.peerconnection; |
|
|
|
|
|
|
|
|
|
//////////////Media/////////START//////
|
|
|
|
|
if (peerconnection) { |
|
|
|
|
peerconnection.addEventListener('addstream', event => { |
|
|
|
|
console.log('Remote stream added:', event.stream); |
|
|
|
|
setRemoteStream(event.stream); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
//////////////Media/////////END////////
|
|
|
|
|
|
|
|
|
|
// Verifica se session.connection está definido e se existem streams locais
|
|
|
|
|
if ( |
|
|
|
|
session.connection && |
|
|
|
|
session.connection.getLocalStreams().length > 0 |
|
|
|
|
) { |
|
|
|
|
const localStreams = session.connection.getLocalStreams()[0]; |
|
|
|
|
localAudio.srcObject = localStreams; |
|
|
|
|
localAudio.volume = 0; |
|
|
|
|
peerconnection.addEventListener('icecandidate', event => { |
|
|
|
|
if (event.candidate) { |
|
|
|
|
console.log('Have NEW ICE Candidate: ', event.candidate); |
|
|
|
|
} |
|
|
|
|
//PAUSA TODOS OS AUDIOS DE FEEDBACK
|
|
|
|
|
incomingCallAudio.pause(); |
|
|
|
|
outgoingCallAudio.pause(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
eventoSip.emit('incall'); |
|
|
|
|
peerconnection.addEventListener('iceconnectionstatechange', () => { |
|
|
|
|
console.log( |
|
|
|
|
'ICE connection state change: ', |
|
|
|
|
peerconnection.iceConnectionState, |
|
|
|
|
); |
|
|
|
|
}); |
|
|
|
|
session.on('icecandidate', function (event) { |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
newSession.on('newDTMF', function (event) { |
|
|
|
|
console.log('DTMF recebido:', event.dtmf.tone); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
newSession.on('confirmed', function (confirmed) { |
|
|
|
|
setScreen('WEBRTC_ROOM'); |
|
|
|
|
}); |
|
|
|
|
newSession.on('icecandidate', function (event) { |
|
|
|
|
if ( |
|
|
|
|
event.candidate.type === 'srflx' && |
|
|
|
|
event.candidate.relatedAddress !== null && |
|
|
|
@ -190,43 +228,9 @@ export default function App({}) {
|
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
session.on('addstream', function (e) { |
|
|
|
|
// Verifica se session.connection está definido
|
|
|
|
|
if (session.connection) { |
|
|
|
|
remoteAudio.srcObject = e.stream; |
|
|
|
|
remoteAudio.play(); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
//RECEBENDO UMA CHAMADA
|
|
|
|
|
if (session.direction === 'incoming') { |
|
|
|
|
incomingCallAudio.play(); |
|
|
|
|
eventoSip.emit('incomingcall', session.remote_identity.uri.user); |
|
|
|
|
|
|
|
|
|
eventoSip.on('rejected', () => { |
|
|
|
|
if (session?.isInProgress()) { |
|
|
|
|
incomingCallAudio.pause(); |
|
|
|
|
eventoSip.emit('home'); |
|
|
|
|
session.terminate(); |
|
|
|
|
session = null; |
|
|
|
|
} else { |
|
|
|
|
eventoSip.emit('home'); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
eventoSip.on('accepted', () => { |
|
|
|
|
if (session?.isInProgress()) { |
|
|
|
|
session.answer(); |
|
|
|
|
incomingCallAudio.pause(); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
//REALIZANDO UMA CHAMADA
|
|
|
|
|
if (session.direction === 'outgoing') { |
|
|
|
|
eventoSip.emit('outgoingcall', session.remote_identity.uri.user); |
|
|
|
|
if (session.isInProgress()) { |
|
|
|
|
outgoingCallAudio.play(); |
|
|
|
|
} |
|
|
|
|
if (newSession.direction === 'outgoing') { |
|
|
|
|
setScreen('OUTGOING_CALL'); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
phone.on('registered', function (e) { |
|
|
|
@ -249,375 +253,104 @@ export default function App({}) {
|
|
|
|
|
eventoSip.emit('statusChange', 'disconnected'); |
|
|
|
|
}); |
|
|
|
|
phone.start(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
setUa(phone); |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
iniciandoAutenticacaonoPBX(); |
|
|
|
|
return () => { |
|
|
|
|
InCallManager.stop(); |
|
|
|
|
phone.stop(); |
|
|
|
|
}; |
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
const [localStream, setlocalStream] = useState(null); |
|
|
|
|
const [remoteStream, setRemoteStream] = useState(null); |
|
|
|
|
const [isSpeakerOn, setIsSpeakerOn] = useState(false); |
|
|
|
|
const [type, setType] = useState('JOIN'); |
|
|
|
|
const [callerId] = useState( |
|
|
|
|
Math.floor(100000 + Math.random() * 900000).toString(), |
|
|
|
|
); |
|
|
|
|
const otherUserId = useRef(null); |
|
|
|
|
const socket = SocketIOClient('http://129.148.58.190:8088', { |
|
|
|
|
transports: ['websocket'], |
|
|
|
|
query: { |
|
|
|
|
callerId, |
|
|
|
|
}, |
|
|
|
|
reconnectionAttempts: 3, |
|
|
|
|
reconnectionDelay: 1000, |
|
|
|
|
}); |
|
|
|
|
const [localMicOn, setlocalMicOn] = useState(true); |
|
|
|
|
const [localWebcamOn, setlocalWebcamOn] = useState(true); |
|
|
|
|
const [iniciarChamada, setIniciarChamada] = useState(false); |
|
|
|
|
let remoteRTCMessage = useRef(null); |
|
|
|
|
const peerConnection = useRef(null); |
|
|
|
|
|
|
|
|
|
const createPeerConnection = () => { |
|
|
|
|
return new RTCPeerConnection({ |
|
|
|
|
iceServers: [ |
|
|
|
|
{ |
|
|
|
|
urls: 'stun:stun.l.google.com:19302', |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
urls: 'stun:stun1.l.google.com:19302', |
|
|
|
|
const handleAceitarChamada = async () => { |
|
|
|
|
if (session) { |
|
|
|
|
session.answer({ |
|
|
|
|
mediaConstraints: { |
|
|
|
|
audio: true, |
|
|
|
|
video: false, |
|
|
|
|
}, |
|
|
|
|
{urls: 'stun:stun2.l.google.com:19302'}, |
|
|
|
|
], |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const initializePeerConnection = async () => { |
|
|
|
|
try { |
|
|
|
|
peerConnection.current = createPeerConnection(); |
|
|
|
|
console.log('PeerConnection initialized successfully.'); |
|
|
|
|
} catch (error) { |
|
|
|
|
console.error('Error initializing PeerConnection:', error); |
|
|
|
|
setScreen('WEBRTC_ROOM'); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
//Função para limpar todos os listeners do socket
|
|
|
|
|
const cleanUp = () => { |
|
|
|
|
try { |
|
|
|
|
if (peerConnection.current) { |
|
|
|
|
peerConnection.current.close(); |
|
|
|
|
} |
|
|
|
|
// Fechar o socket e remover os listeners
|
|
|
|
|
socket.off('newCall'); |
|
|
|
|
socket.off('callAnswered'); |
|
|
|
|
socket.off('ICEcandidate'); |
|
|
|
|
socket.close(); |
|
|
|
|
|
|
|
|
|
// Parar o InCallManager e fechar a conexão Peer
|
|
|
|
|
const handleRejectCall = () => { |
|
|
|
|
if (session) { |
|
|
|
|
session.terminate(); |
|
|
|
|
setSession(null); |
|
|
|
|
setIncomingCaller(null); |
|
|
|
|
InCallManager.stop(); |
|
|
|
|
|
|
|
|
|
// Parar e remover os fluxos de mídia
|
|
|
|
|
if (localStream) { |
|
|
|
|
localStream.getTracks().forEach(track => track.stop()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Limpar o estado localStream e remoteRTCMessage
|
|
|
|
|
setlocalStream(null); |
|
|
|
|
remoteRTCMessage.current = null; |
|
|
|
|
|
|
|
|
|
if (peerConnection.current) { |
|
|
|
|
peerConnection.current.onconnectionstatechange = function () { |
|
|
|
|
console.log('--->' + peerConnection.current.connectionState); |
|
|
|
|
}; |
|
|
|
|
} else { |
|
|
|
|
console.error( |
|
|
|
|
'O objeto peerConnection.current não está definido ou é nulo.', |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
console.log('Limpeza concluída com sucesso.'); |
|
|
|
|
} catch (error) { |
|
|
|
|
console.error('Erro durante a limpeza:', error); |
|
|
|
|
// Lidar com o erro de limpeza aqui, se necessário
|
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const socketConfig = () => { |
|
|
|
|
console.log('Iniciando a conexão com o socket'); |
|
|
|
|
|
|
|
|
|
socket.on('newCall', data => { |
|
|
|
|
console.log('Received new call'); |
|
|
|
|
remoteRTCMessage.current = data.rtcMessage; |
|
|
|
|
otherUserId.current = data.callerId; |
|
|
|
|
setType('INCOMING_CALL'); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
socket.on('callAnswered', data => { |
|
|
|
|
console.log('Call answered'); |
|
|
|
|
remoteRTCMessage.current = data.rtcMessage; |
|
|
|
|
try { |
|
|
|
|
peerConnection.current.setRemoteDescription( |
|
|
|
|
new RTCSessionDescription(remoteRTCMessage.current), |
|
|
|
|
); |
|
|
|
|
setType('WEBRTC_ROOM'); |
|
|
|
|
} catch (error) { |
|
|
|
|
console.log('Erro ao atender chamada: ', error); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const closePeerConnection = () => { |
|
|
|
|
if (peerConnection.current) { |
|
|
|
|
console.log('Closing peer connection'); |
|
|
|
|
peerConnection.current.close(); |
|
|
|
|
peerConnection.current = null; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// No cliente, ouvir o evento "endCallAndLeaveRoom" do servidor
|
|
|
|
|
socket.on('endCallAndLeaveRoom', () => { |
|
|
|
|
// Deixar a sala após encerrar a chamada
|
|
|
|
|
socket.emit('leaveRoom'); // Envia um evento para o servidor para deixar a sala
|
|
|
|
|
closePeerConnection(); |
|
|
|
|
setlocalStream(null); |
|
|
|
|
setType('JOIN'); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// Lógica para sair da sala no cliente
|
|
|
|
|
socket.on('leaveRoom', () => { |
|
|
|
|
socket.leave(socket.user); // Deixa a sala com o mesmo nome do usuário
|
|
|
|
|
console.log(`${socket.user} left the conference room.`); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
socket.on('ICEcandidate', data => { |
|
|
|
|
let message = data.rtcMessage; |
|
|
|
|
|
|
|
|
|
if (peerConnection.current) { |
|
|
|
|
peerConnection.current |
|
|
|
|
.addIceCandidate( |
|
|
|
|
new RTCIceCandidate({ |
|
|
|
|
candidate: message.candidate, |
|
|
|
|
sdpMid: message.id, |
|
|
|
|
sdpMLineIndex: message.label, |
|
|
|
|
}), |
|
|
|
|
) |
|
|
|
|
.then(data => { |
|
|
|
|
console.log('Added ICE candidate successfully:', message); |
|
|
|
|
}) |
|
|
|
|
.catch(err => { |
|
|
|
|
console.log('Error adding ICE candidate:', err); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
const handleIniciarChamada = () => { |
|
|
|
|
console.log('AQUI:::::::' + calle); |
|
|
|
|
if (ua && calle) { |
|
|
|
|
const eventHandlers = { |
|
|
|
|
progress: () => { |
|
|
|
|
console.log('Call is in progress'); |
|
|
|
|
}, |
|
|
|
|
failed: e => { |
|
|
|
|
console.log('Call failed with cause: ' + e.cause); |
|
|
|
|
InCallManager.stop(); |
|
|
|
|
}, |
|
|
|
|
ended: () => { |
|
|
|
|
console.log('Call ended'); |
|
|
|
|
InCallManager.stop(); |
|
|
|
|
}, |
|
|
|
|
confirmed: () => { |
|
|
|
|
console.log('Call confirmed'); |
|
|
|
|
InCallManager.setForceSpeakerphoneOn(true); |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const mediaConfig = async () => { |
|
|
|
|
try { |
|
|
|
|
const devices = await mediaDevices.enumerateDevices(); |
|
|
|
|
let isFront = true; |
|
|
|
|
let videoSourceId = null; |
|
|
|
|
|
|
|
|
|
devices.forEach(device => { |
|
|
|
|
if ( |
|
|
|
|
device.kind === 'videoinput' && |
|
|
|
|
device.facingMode === (isFront ? 'user' : 'environment') |
|
|
|
|
) { |
|
|
|
|
videoSourceId = device.deviceId; |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const constraints = { |
|
|
|
|
const options = { |
|
|
|
|
eventHandlers: eventHandlers, |
|
|
|
|
mediaConstraints: { |
|
|
|
|
audio: true, |
|
|
|
|
video: false, |
|
|
|
|
// video: {
|
|
|
|
|
// mandatory: {
|
|
|
|
|
// minWidth: 500,
|
|
|
|
|
// minHeight: 300,
|
|
|
|
|
// minFrameRate: 30,
|
|
|
|
|
// },
|
|
|
|
|
// facingMode: isFront ? 'user' : 'environment',
|
|
|
|
|
// },
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
if (videoSourceId) { |
|
|
|
|
constraints.video.optional = [{sourceId: videoSourceId}]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const stream = await mediaDevices.getUserMedia(constraints); |
|
|
|
|
setlocalStream(stream); |
|
|
|
|
|
|
|
|
|
peerConnection.current.addStream(stream); |
|
|
|
|
|
|
|
|
|
peerConnection.current.onaddstream = event => { |
|
|
|
|
setRemoteStream(event.stream); |
|
|
|
|
}; |
|
|
|
|
} catch (error) { |
|
|
|
|
console.error('Error accessing media devices:', error); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const handleIniciarChamada = async () => { |
|
|
|
|
setIniciarChamada(true); |
|
|
|
|
await initializeApp(); // Aguarda a conclusão da inicialização
|
|
|
|
|
setType('OUTGOING_CALL'); |
|
|
|
|
await processCall(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const handleAceitarChamada = async () => { |
|
|
|
|
setType('WEBRTC_ROOM'); |
|
|
|
|
await processAccept(); |
|
|
|
|
}, |
|
|
|
|
rtcOfferContraints: { |
|
|
|
|
offerToReceiveAudio: true, |
|
|
|
|
offerToReceiveVideo: false, |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
async function initializeApp() { |
|
|
|
|
try { |
|
|
|
|
await initializePeerConnection(); |
|
|
|
|
await mediaConfig(); |
|
|
|
|
socketConfig(); |
|
|
|
|
const newSession = ua.call(`sip:${calle}@${servidor}`, options); |
|
|
|
|
console.log('URI: ' + `sip:${calle}@${servidor}`); |
|
|
|
|
setSession(newSession); |
|
|
|
|
|
|
|
|
|
peerConnection.current.addEventListener('signalingstatechange', event => { |
|
|
|
|
console.log( |
|
|
|
|
'Signaling state changed:', |
|
|
|
|
event.type, |
|
|
|
|
':', |
|
|
|
|
peerConnection.current.signalingState, |
|
|
|
|
); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
setIniciarChamada(false); |
|
|
|
|
} catch (error) { |
|
|
|
|
console.error('Erro durante a inicialização:', error); |
|
|
|
|
// Trate o erro conforme necessário
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
initializeApp(); |
|
|
|
|
setIniciarChamada(false); |
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
if (iniciarChamada) { |
|
|
|
|
initializeApp(); |
|
|
|
|
setIniciarChamada(false); |
|
|
|
|
InCallManager.start({media: 'audio'}); |
|
|
|
|
} |
|
|
|
|
}, [iniciarChamada]); |
|
|
|
|
|
|
|
|
|
//useEffect para iniciar o gerenciamento de chamadas
|
|
|
|
|
useEffect(() => { |
|
|
|
|
const callOptions = { |
|
|
|
|
media: 'audioVideo', |
|
|
|
|
}; |
|
|
|
|
InCallManager.start(callOptions); |
|
|
|
|
InCallManager.setKeepScreenOn(true); |
|
|
|
|
InCallManager.setForceSpeakerphoneOn(true); |
|
|
|
|
|
|
|
|
|
setIniciarChamada(false); |
|
|
|
|
return () => { |
|
|
|
|
InCallManager.stop(); |
|
|
|
|
}; |
|
|
|
|
}, [iniciarChamada]); |
|
|
|
|
|
|
|
|
|
function sendICEcandidate(data) { |
|
|
|
|
socket.emit('ICEcandidate', data); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async function processCall() { |
|
|
|
|
console.log('Processing call...'); |
|
|
|
|
InCallManager.startRingback(); |
|
|
|
|
const sessionDescription = await peerConnection.current.createOffer(); |
|
|
|
|
await peerConnection.current.setLocalDescription(sessionDescription); |
|
|
|
|
sendCall({ |
|
|
|
|
calleeId: otherUserId.current, |
|
|
|
|
rtcMessage: sessionDescription, |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async function processAccept() { |
|
|
|
|
console.log('Processing call acceptance...'); |
|
|
|
|
try { |
|
|
|
|
await peerConnection.current.setRemoteDescription( |
|
|
|
|
new RTCSessionDescription(remoteRTCMessage.current), |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
const sessionDescription = await peerConnection.current.createAnswer(); |
|
|
|
|
await peerConnection.current.setLocalDescription(sessionDescription); |
|
|
|
|
|
|
|
|
|
answerCall({ |
|
|
|
|
callerId: otherUserId.current, |
|
|
|
|
rtcMessage: sessionDescription, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// Adicionar evento onicecandidate após a criação da resposta local
|
|
|
|
|
peerConnection.current.onicecandidate = event => { |
|
|
|
|
if (event.candidate) { |
|
|
|
|
// Enviar ICE candidate apenas quando estiver disponível
|
|
|
|
|
sendICEcandidate({ |
|
|
|
|
calleeId: otherUserId.current, |
|
|
|
|
rtcMessage: { |
|
|
|
|
label: event.candidate.sdpMLineIndex, |
|
|
|
|
id: event.candidate.sdpMid, |
|
|
|
|
candidate: event.candidate.candidate, |
|
|
|
|
}, |
|
|
|
|
const toggleMic = () => { |
|
|
|
|
console.log('Toggling microphone...'); |
|
|
|
|
localMicOn ? setlocalMicOn(false) : setlocalMicOn(true); |
|
|
|
|
localStream.getAudioTracks().forEach(track => { |
|
|
|
|
localMicOn ? (track.enabled = false) : (track.enabled = true); |
|
|
|
|
}); |
|
|
|
|
} else { |
|
|
|
|
console.log('End of candidates.'); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} catch (error) { |
|
|
|
|
console.error('Error processing call acceptance:', error); |
|
|
|
|
// Tratar o erro conforme necessário
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function answerCall(data) { |
|
|
|
|
socket.emit('answerCall', data); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function sendCall(data) { |
|
|
|
|
socket.emit('call', data); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function endCall(data) { |
|
|
|
|
socket.emit('endCall', data); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function switchCamera() { |
|
|
|
|
localStream.getVideoTracks().forEach(track => { |
|
|
|
|
track._switchCamera(); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function toggleCamera() { |
|
|
|
|
const toggleCamera = () => { |
|
|
|
|
console.log('Toggling camera...'); |
|
|
|
|
localWebcamOn ? setlocalWebcamOn(false) : setlocalWebcamOn(true); |
|
|
|
|
localStream.getVideoTracks().forEach(track => { |
|
|
|
|
localWebcamOn ? (track.enabled = false) : (track.enabled = true); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function toggleMic() { |
|
|
|
|
console.log('Toggling microphone...'); |
|
|
|
|
localMicOn ? setlocalMicOn(false) : setlocalMicOn(true); |
|
|
|
|
localStream.getAudioTracks().forEach(track => { |
|
|
|
|
localMicOn ? (track.enabled = false) : (track.enabled = true); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function toggleSpeaker() { |
|
|
|
|
console.log('Toggling speaker...'); |
|
|
|
|
setIsSpeakerOn(!isSpeakerOn); |
|
|
|
|
InCallManager.setSpeakerphoneOn(!isSpeakerOn); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
function cancelCall() { |
|
|
|
|
setType('JOIN'); |
|
|
|
|
InCallManager.stopRingback(); |
|
|
|
|
otherUserId.current = null; |
|
|
|
|
} |
|
|
|
|
// useEffect(() => {
|
|
|
|
|
// if (remoteStream && remoteAudio.current) {
|
|
|
|
|
// remoteAudio.current = remoteStream;
|
|
|
|
|
// remoteAudio.current.play();
|
|
|
|
|
// }
|
|
|
|
|
// }, [remoteStream]);
|
|
|
|
|
|
|
|
|
|
function leave() { |
|
|
|
|
// Emitir o evento 'endCall' para o servidor
|
|
|
|
|
endCall({otherPeer: otherUserId.current}); |
|
|
|
|
setType('JOIN'); |
|
|
|
|
} |
|
|
|
|
// useEffect(() => {
|
|
|
|
|
// if (localAudio.current && localStream) {
|
|
|
|
|
// localAudio.current = localStream;
|
|
|
|
|
// }
|
|
|
|
|
// }, [localStream]);
|
|
|
|
|
|
|
|
|
|
const styles = StyleSheet.create({ |
|
|
|
|
container: { |
|
|
|
@ -684,7 +417,7 @@ export default function App({}) {
|
|
|
|
|
<View style={styles.inner}> |
|
|
|
|
<Text style={styles.titles}>Seu ID para ligação</Text> |
|
|
|
|
<View style={styles.box}> |
|
|
|
|
<Text style={styles.idCall}>{callerId}</Text> |
|
|
|
|
<Text style={styles.idCall}>{myRamal}</Text> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
<TouchableWithoutFeedback onPress={Keyboard.dismiss}> |
|
|
|
@ -693,10 +426,9 @@ export default function App({}) {
|
|
|
|
|
<Text style={styles.titles}>Ligação</Text> |
|
|
|
|
<TextInputContainer |
|
|
|
|
placeholder={'Insira o ID para ligação'} |
|
|
|
|
value={otherUserId.current} |
|
|
|
|
value={calle} |
|
|
|
|
setValue={text => { |
|
|
|
|
otherUserId.current = text; |
|
|
|
|
console.log('TEST', otherUserId.current); |
|
|
|
|
setCalle(text); |
|
|
|
|
}} |
|
|
|
|
keyboardType={'number-pad'} |
|
|
|
|
/> |
|
|
|
@ -744,7 +476,7 @@ export default function App({}) {
|
|
|
|
|
color: '#ffff', |
|
|
|
|
letterSpacing: 6, |
|
|
|
|
}}> |
|
|
|
|
{otherUserId.current} |
|
|
|
|
{calle} |
|
|
|
|
</Text> |
|
|
|
|
</View> |
|
|
|
|
<View |
|
|
|
@ -792,7 +524,7 @@ export default function App({}) {
|
|
|
|
|
marginTop: 15, |
|
|
|
|
color: '#ffff', |
|
|
|
|
}}> |
|
|
|
|
Recebendo ligação de {otherUserId.current} |
|
|
|
|
Recebendo ligação de {incomingCaller} |
|
|
|
|
</Text> |
|
|
|
|
</View> |
|
|
|
|
<View |
|
|
|
@ -833,7 +565,7 @@ export default function App({}) {
|
|
|
|
|
|
|
|
|
|
<TouchableOpacity |
|
|
|
|
onPress={() => { |
|
|
|
|
cancelCall(); |
|
|
|
|
handleRejectCall(); |
|
|
|
|
}}> |
|
|
|
|
<Animatable.View |
|
|
|
|
animation="pulse" |
|
|
|
@ -976,7 +708,7 @@ export default function App({}) {
|
|
|
|
|
); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
switch (type) { |
|
|
|
|
switch (screen) { |
|
|
|
|
case 'JOIN': |
|
|
|
|
return JoinScreen(); |
|
|
|
|
case 'INCOMING_CALL': |
|
|
|
|