Closed prototypeninja closed 3 months ago
Hi @prototypeninja, thanks for reaching out. For future issues, please make sure to fill out the issue template, it helps us out a lot with debugging issues and is not optional.
For your current issue, you can listen for the voice.on(Voice.Event.CallInviteAccepted, (call) => { call.on(Call.Event.Disconnected, ...) })
event. The internal Disconnected
event should fire for outgoing and incoming calls.
Please note that this API will actually be changing in the next release for better developer ergonomics.
voice.on(Voice.Event.CallInviteAccepted,(call) => { console.log('call accept'); call.on(Call.Event.Disconnected,()=>{ console.log('call Disconnected'); }) }, ); TypeError: call.on is not a function (it is undefined), js engine: hermes
Hi @prototypeninja I see, this is not an issue that we've seen before. Can you provide a more complete code snippet if possible? And can you please describe your environment in more detail, are you using a physical Android device or the emulator? What version of Android, etc.
Good evening. Thank you for your reply. I am using a physical android 13 android phone. here is the conde of the context in full
`import React, { createContext, useContext, useState, useEffect } from 'react'; import { Voice,Call as TwilioCall, Call } from '@twilio/voice-react-native-sdk'; import { getUsers,getContactByNumber } from '../database/database'; import { useSelector,useDispatch } from 'react-redux'; import { updateAuth } from './reducers'; import { AppState } from 'react-native'; import { updatecalldata } from '../api/api'; import BackgroundService from 'react-native-background-actions'; import NetInfo from "@react-native-community/netinfo";
const sleep = (time) => new Promise((resolve) => setTimeout(() => resolve(), time));
var myHeaders = new Headers(); myHeaders.append("Content-Type", "application/json"); const VoiceContext = createContext();
export const VoiceProvider = ({ children }) => { const isAuthenticated = useSelector((state) => state.data.isAuthenticated); const dispatch = useDispatch(); const [token, setToken] = useState(''); const [callinvite, setcallinvite] = useState(null); const [isLoad, setIsLoad] = useState(false); const [currentcontact, setcurrentcontact] = useState(false); const [callconnected, setcallconnected] = useState(false);
const [isRunning, setIsRunning] = useState(false);
const [elapsedTime, setElapsedTime] = useState(0);
const [callstatus, setcallstatus]=useState('')
const [currentcall, setcurrentcall]=useState(null)
const [currentsid, setcurrentsid]=useState(null)
const [currentnumber, setcurrentnumber] = useState(null);
const [ismute, setismute] = useState(false);
const [iswait, setiswait] = useState(false);
const [appState, setAppState] = useState(AppState.currentState);
const [appStateVisible, setAppStateVisible] = useState(appState.current);
const sendUpdateRequest=(id)=> {
return new Promise((resolve, reject) => {
console.log("datauser.length00000000000000000")
console.log(id)
var raw = JSON.stringify({
"jsonrpc": "2.0",
"params": {
id:id,
"token": "token"
}
});
console.log(raw)
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
};
NetInfo.fetch().then(state => {
if (state.isConnected && state.isInternetReachable) {
fetch("https://domaine/api/openit/updateusersate", requestOptions)
.then(response => response.json())
.then(result => resolve(result))
.catch(error => reject(error) );
} else {
resolve("Pas de connexion Internet disponible.")
// console.log("Pas de connexion Internet disponible.");
}
});
})
}
const veryIntensiveTask = async (taskDataArguments) => { const { delay } = taskDataArguments; await new Promise(async (resolve) => { for (let i = 0; BackgroundService.isRunning(); i++) { console.log(i);
// Effectuer la requête HTTP toutes les 15 secondes
const usersate= await sendUpdateRequest(datauser[0].id);
console.log(usersate)
await sleep(delay);
}
});
};
const options = { taskName: 'OpenitUpdate', taskTitle: 'User status update', taskDesc: "Checking the user's statue", taskIcon: { name: 'ic_launcher', type: 'mipmap', }, color: '#ff00ff', parameters: { delay: 15000, // 15 secondes }, };
useEffect(() => { const subscription = AppState.addEventListener('change', nextAppState => { console.log("appStateappStateappStateappStateappStateappStateappState") console.log(appState) if ( appState.match(/inactive|background/) && nextAppState === 'active' ) { console.log('App has come to the foreground!'); BackgroundService.stop(); } else if (appState.match(/active/) && nextAppState.match(/inactive|background/)) { // L'application est passée de l'état actif (en premier plan) à l'état background/inactive // Démarrez le service ici si nécessaire if(datauser.length>0){ BackgroundService.start(veryIntensiveTask, options);
}
}
console.log('AppState', nextAppState);
setAppState(nextAppState);
});
return () => {
subscription.remove();
};
}, [appState]); // <-- Add appState to the dependency array
const updateactive=async ()=>{ if(datauser.length>0){ const usersate= await sendUpdateRequest(datauser[0].id); console.log(usersate) }
}
useEffect(() => { let interval; interval = setInterval(() => { updateactive() }, 15000);
return () => {
clearInterval(interval);
};
}, []);
useEffect(() => {
let interval;
if (isRunning) {
interval = setInterval(() => {
setElapsedTime((prevTime) => prevTime + 1000); // Ajoute 1 seconde à chaque intervalle
}, 1000);
}
return () => {
clearInterval(interval);
};
}, [isRunning]);
const startStop = () => {
setIsRunning((prevState) => !prevState);
};
const reset = () => {
setIsRunning(false);
setElapsedTime(0);
};
const formatTime = (milliseconds) => {
const seconds = Math.floor((milliseconds / 1000) % 60);
const minutes = Math.floor((milliseconds / (1000 * 60)) % 60);
const hours = Math.floor(milliseconds / (1000 * 60 * 60));
const formatNumber = (number) => (number < 10 ? `0${number}` : number);
return `${formatNumber(hours)}:${formatNumber(minutes)}:${formatNumber(seconds)}`;
};
const datauser = getUsers();
const voice = new Voice();
const fetchToken = async (id) => {
try {
const userId = `mobile-${id}`;
const response = await fetch(`https://domaine/voip/app/token/?id=${userId}`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
console.log("data.token(data.token")
console.log(data.token)
await voice.register(data.token);
console.log("6666666666666666666666")
voice.on(Voice.Event.Registered, () => {
console.log('Registrered');
});
voice.on('callInvite', (callInvite) => {
console.log('callInvite');
setcallinvite(callInvite);
});
voice.on(Voice.Event.CallInviteNotificationTapped, (call) => {
console.log('notification touch');
});
voice.on(Voice.Event.CallInviteAccepted,(call) => {
console.log('call accept');
call.on(Call.Event.Disconnected,()=>{
console.log('call Disconnected');
})
},
);
voice.on(Voice.Event.CallInviteRejected, () => {
console.log('CallInviteRejected');
});
voice.on( Voice.Event.CancelledCallInvite,
() => {
console.log('CancelledCallInvite');
}
);
setToken(data.token);
} catch (error) {
console.log('There was a problem with the fetch operation:', error);
}
};
useEffect(() => {
if(datauser.length!=0){
dispatch(updateAuth({ key: 'token', value: token }));
}
}, [token,datauser]);
useEffect(() => {
console.log('ffffffffff')
// console.log(token.trim())
if(datauser.length!=0){
if(token.trim()==''){
console.log('eee')
fetchToken(datauser[0].id).then(res=>{
console.log('done')
})
}
// BackgroundService.stop()
}
}, [datauser]);
useEffect(() => {
console.log(callinvite)
// if(callinvite!=null){
// callinvite.on(TwilioCall.Event.ConnectFailure, async (error) =>{
// console.log('callinvite ConnectFailure')
// })
// callinvite.on(TwilioCall.Event.Reconnecting, (error) =>{
// console.log('callinvite reconnexion')
// } )
// callinvite.on(TwilioCall.Event.Disconnected, async (error) => {
// console.log('callinvite Disconnected')
// });
// callinvite.once(TwilioCall.Event.QualityWarningsChanged, (error) => {
// console.log('callinvite QualityWarningsChanged')
// });
// callinvite.once(TwilioCall.Event.Connected, async () => {
// setcallstatus('callinvite QualityWarningsChanged')
// })
// }
}, [callinvite])
const makecall=async (number)=>{
const contactFound = getContactByNumber(number);
console.log(contactFound)
if(contactFound.length!==0){
setcurrentcontact(contactFound[0])
}else{
setcurrentcontact(false)
}
const call = await voice.connect(token,{
params: {
To: number.replace(/[^\d]/g, ''),
},
});
setcurrentnumber(number)
call.on(TwilioCall.Event.ConnectFailure, async (error) =>{
console.log('ConnectFailure----:', error)
console.log('ConnectFailure sid:', call.getSid());
console.log(datauser[0].id)
const dataupdate =await updatecalldata('domaine',call.getSid(),elapsedTime,datauser[0].id)
setcallstatus('Disconnected')
setcallconnected(false)
setcurrentcall(null)
setcurrentnumber(null)
setcurrentsid(null)
reset()
}
// navigation.goBack()
);
call.on(TwilioCall.Event.Reconnecting, (error) =>
console.log('Reconnecting:', error),
);
call.on(TwilioCall.Event.Disconnected, async (error) => {
// The type of error here is "TwilioError | undefined".
console.log('Disconnected',currentsid)
console.log('Disconnected sid:', call.getSid());
console.log('elapsedTime sid:', elapsedTime);
console.log(datauser[0].id)
const dataupdate =await updatecalldata('domaine',call.getSid(),elapsedTime,datauser[0].id)
console.log('55555555555555555',dataupdate)
setcallstatus('Disconnected')
setcallconnected(false)
setcurrentcall(null);
setcurrentnumber(null)
setcurrentsid(null)
reset()
});
call.on(TwilioCall.Event.Ringing, async (error) => {
// The type of error here is "TwilioError | undefined".
// navigation.goBack()
setcallstatus('Ringing')
setcallconnected(false)
console.log('Ringing sid:', call.getSid());
if(currentsid==null){
setcurrentsid(call.getSid())
}
console.log(call.listeners())
});
call.once(TwilioCall.Event.QualityWarningsChanged, (error) => {
console.log('Ringing:', error);
});
call.once(TwilioCall.Event.Connected, async () => {
setcallstatus('Connected')
setcallconnected(true)
console.log('Connected sid:', call.getSid());
console.log('Connected',currentsid)
startStop()
})
setcurrentcall(call)
}
const rejectCall = async () => {
if (!currentcall) {
console.warn('No call invite to reject');
} else {
await currentcall.disconnect();
}
}
const senddigit = async (digit) => {
if (!currentcall) {
console.warn('No call invite to reject');
} else {
await currentcall.sendDigits(digit);
}
}
const togglemute = async () => {
if (!currentcall) {
console.warn('No call invite to reject');
} else {
await currentcall.mute(!ismute);
setismute((prevState) => !prevState);
}
}
const voiceContextValue = {
callinvite,
makecall,
isRunning,
elapsedTime,
startStop,
reset,
formatTime,
currentcontact,
callconnected,
callstatus,
currentcall,
rejectCall,
setcallstatus,
currentnumber,
senddigit,
iswait,
ismute,
togglemute
};
return <VoiceContext.Provider value={voiceContextValue}>{children}</VoiceContext.Provider>;
}
export const useVoice = () => { const context = useContext(VoiceContext); if (!context) { throw new Error('useVoice must be used within a VoiceProvider'); } return context; };
`
Hi @prototypeninja my apologies, the function signature of the Voice.Listener.CallInviteAccepted
function should be (callInvite, call) => any
, not what I previously mentioned. Your code should look like this instead
voice.on(Voice.Event.CallInviteAccepted, (callInvite, call) => {
call.on(Call.Event.Disconnected, () => {
...
});
});
You can view the API docs for the version of the library that you're using by navigating to the tag in GitHub and going to docs/api/voice-react-native-sdk.md
.
thank you it worked
Good morning. I would like to know on Android how to know that an incoming call has ended after accepting it from the notification. The disconneted event only works for outgoing calls I use this version "@twilio/voice-react-native-sdk": "^1.0.0-rc8",