These are my issues on github:
Video Starts on Hold and Muted, Audio Call Starts Muted
CallKeep Not Keeping Call in IOS
I Could not fix these issues and I still only hear Audio for Audio calls when I press (hold) and then press (unhold) and only see video and hear audio in Video Calls when doing the same, I tried to fix this by installing react-native-incall-manager
but this has now just given me different issues to deal with, why is nothing working ? Now I’m hearing the speaker of 1 phone during call but nothing from the other phone. I can see video on both but only after doing this:
useEffect(() => {
if (ready && session.current) {
setTimeout(() => {
Wazo.Phone.hold(session.current);
console.log('simulate hold');
dispatch({ held: true });
}, 1000);
setTimeout(() => {
console.log('simulate unhold');
if (session.current?.cameraEnabled) {
inCallManager.start({ media: 'video' });
} else if (session.current) {
inCallManager.start({ media: 'audio' });
inCallManager.setForceSpeakerphoneOn(false);
}
Wazo.Phone.unhold(session.current);
dispatch({ held: false });
}, 2000);
}
}, [ready]);
It really is getting absurd what I’m having to do to get the calls to work, these libs are all broken and don’t work mashed together like all the readme’s are saying. Here is my full code in the hope that someone might be out there:
import React, { useReducer, useEffect, useRef } from 'react';
import {
StyleSheet,
View,
Dimensions,
Platform,
TextInput,
TouchableOpacity,
} from 'react-native';
import inCallManager from 'react-native-incall-manager';
import RNCallKeep from 'react-native-callkeep';
import { RTCView, registerGlobals } from 'react-native-webrtc';
import { v4 as uuid } from 'uuid';
import Wazo from '@wazo/sdk/lib/simple';
import AsyncStorage from '@react-native-community/async-storage';
import CommonText from '../components/common/text/common_text';
export const OUTGOING = [
'ON_CALL_OUTGOING',
'ON_PROGRESS',
'ON_CALL_ACCEPTED',
'ON_CALL_ENDED',
];
export const INCOMING = [
'ON_CALL_INCOMING',
'ON_CALL_ANSWERED',
'ON_CALL_ACCEPTED',
'ON_CALL_ENDED',
];
// Polyfill WebRTC
registerGlobals();
const options = {
ios: { appName: 'euclid', includesCallsInRecents: false },
android: {
additionalPermissions: [],
alertTitle: 'Permission Required',
alertDescription: 'This application needs to access to allow calls',
okButton: 'Ok',
cancelButton: 'Cancel',
},
};
const isIOS = Platform.OS === 'ios';
const Dialer = ({ setLogout }: { setLogout: () => void }) => {
const reducer = (state: any, action: any) => ({ ...state, ...action });
const initialState = {
ext: '',
isCall: false,
ready: false,
held: false,
cameraOn: false,
};
const [state, dispatch] = useReducer(reducer, initialState);
const { ext, isCall, ready, held, cameraOn } = state;
const session = useRef<any>(null);
const callId = useRef<string>('');
const remote = useRef<any>(null);
const local = useRef<any>(null);
const call = async (num: any, video = false) => {
if (!num || isCall) return;
try {
await Wazo.Phone.call(num, video);
} catch (err) {
console.warn(err);
}
};
const terminate = () => {
dispatch(initialState);
session.current = null;
local.current = null;
remote.current = null;
callId.current = '';
inCallManager.stop();
};
const oneTimeId = () => {
callId.current = callId.current || uuid();
return callId.current;
};
const initializeWebRtc = async () => {
await Wazo.Phone.connect({ audio: true, video: true });
Wazo.Phone.on(Wazo.Phone.ON_CALL_REINVITE, () =>
console.log('reinvite occuring')
);
Wazo.Phone.on(Wazo.Phone.ON_CALL_OUTGOING, (outgoingSess: any) => {
dispatch({ isCall: true });
session.current = outgoingSess;
const { number, displayName, cameraEnabled } = outgoingSess;
RNCallKeep.startCall(
oneTimeId(),
number,
displayName,
'number',
cameraEnabled
);
});
Wazo.Phone.on(Wazo.Phone.ON_CALL_INCOMING, (incomingSess: any) => {
dispatch({ isCall: true });
session.current = incomingSess;
const { number, displayName, cameraEnabled } = incomingSess;
RNCallKeep.displayIncomingCall(
oneTimeId(),
number,
displayName,
'number',
cameraEnabled
);
});
Wazo.Phone.on(Wazo.Phone.ON_CALL_FAILED, () => {
const id = oneTimeId();
terminate();
RNCallKeep.endCall(id);
});
Wazo.Phone.on(Wazo.Phone.ON_CALL_ENDED, () => {
const id = oneTimeId();
terminate();
RNCallKeep.endCall(id);
});
Wazo.Phone.on(Wazo.Phone.ON_CALL_ACCEPTED, async (acceptedSess: any) => {
if (isCall) return;
session.current = acceptedSess;
if (session.current?.cameraEnabled) {
const sipSession = Wazo.Phone.getCurrentSipSession();
const { peerConnection } = sipSession.sessionDescriptionHandler;
const lStreams = peerConnection.getLocalStreams();
const rStreams = peerConnection.getRemoteStreams();
const anyStream = (stream: any) => !!stream.getVideoTracks().length;
local.current = lStreams.find(anyStream);
remote.current = rStreams.find(anyStream);
}
// @ts-ignore
RNCallKeep.setCurrentCallActive(oneTimeId());
dispatch({ ready: true });
});
};
useEffect(() => {
if (ready && session.current) {
setTimeout(() => {
Wazo.Phone.hold(session.current);
console.log('simulate hold');
dispatch({ held: true });
}, 1000);
setTimeout(() => {
console.log('simulate unhold');
if (session.current?.cameraEnabled) {
inCallManager.start({ media: 'video' });
} else if (session.current) {
inCallManager.start({ media: 'audio' });
inCallManager.setForceSpeakerphoneOn(false);
}
Wazo.Phone.unhold(session.current);
dispatch({ held: false });
}, 2000);
}
}, [ready]);
const handleAnswer = async () =>
Wazo.Phone.accept(session.current, session.current?.cameraEnabled);
const handleHangup = async () => {
if (!session.current) return;
try {
await Wazo.Phone.hangup(session.current);
} catch (err) {
console.warn(err);
}
terminate();
};
const logout = async () => {
await handleHangup();
await Wazo.Auth.logout();
await AsyncStorage.removeItem('call-session-token');
setLogout();
};
const handleMute = (muted: boolean) => {
Wazo.Phone[muted ? 'mute' : 'unmute'](session.current);
};
const initializeCallKeep = () => {
RNCallKeep.setup(options);
RNCallKeep.setAvailable(true);
RNCallKeep.addEventListener('answerCall', handleAnswer);
RNCallKeep.addEventListener('endCall', handleHangup);
RNCallKeep.addEventListener('didPerformSetMutedCallAction', handleMute);
};
const initialize = async () => {
await initializeWebRtc();
initializeCallKeep();
};
const uninitialize = () => {
Wazo.Phone.unbind();
RNCallKeep.removeEventListener('answerCall');
RNCallKeep.removeEventListener('endCall');
RNCallKeep.removeEventListener('didPerformSetMutedCallAction');
};
useEffect(() => {
initialize();
return uninitialize;
}, []);
const toggleHold = () => {
Wazo.Phone[held ? 'unhold' : 'hold'](session.current);
console.log('hold', !held);
dispatch({ held: !held });
};
const toggleCamera = () => {
Wazo.Phone[cameraOn ? 'turnCameraOn' : 'turnCameraOff'](session.current);
dispatch({ cameraOn: !cameraOn });
};
const isVideo = session.current?.cameraEnabled;
return (
<View style={{ flex: 1 }}>
<View>
<View style={{ marginTop: 40, flexDirection: 'row' }}>
<TextInput
style={styles.input}
autoCapitalize='none'
onChangeText={value => dispatch({ ext: value })}
value={ext}
/>
<TouchableOpacity style={styles.button} onPress={logout}>
<CommonText style={{ color: 'white' }}>Logout</CommonText>
</TouchableOpacity>
</View>
<View
style={{
height: '60%',
width: '100%',
}}>
{remote.current && isCall && ready && (
<View style={{ borderColor: 'red', borderWidth: 5, flex: 1 }}>
<RTCView
objectFit='cover'
streamURL={remote.current?.toURL()}
style={styles.remoteVideo}
zOrder={15}
/>
</View>
)}
</View>
{!isCall && (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity
onPress={() => call(ext, false)}
style={styles.button}>
<CommonText style={{ color: 'white' }}>Call</CommonText>
</TouchableOpacity>
<TouchableOpacity
onPress={() => call(ext, true)}
style={styles.button}>
<CommonText style={{ color: 'white' }}>Video call</CommonText>
</TouchableOpacity>
</View>
)}
{!isIOS && local.current && isCall && ready && (
<RTCView
mirror
streamURL={local.current?.toURL()}
style={styles.localVideo}
zOrder={1}
/>
)}
{isIOS && local.current && isCall && ready && (
<RTCView
mirror
streamURL={local.current?.toURL()}
style={styles.localVideo}
zOrder={1}
/>
)}
{isCall && (
<>
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity onPress={handleHangup} style={styles.button}>
<CommonText style={{ color: 'white' }}>Hangup</CommonText>
</TouchableOpacity>
<TouchableOpacity onPress={toggleHold} style={styles.button}>
<CommonText style={{ color: 'white' }}>
{held ? 'Unhold' : 'Hold'}
</CommonText>
</TouchableOpacity>
</View>
{isVideo && (
<TouchableOpacity onPress={toggleCamera} style={styles.button}>
<CommonText style={{ color: 'white' }}>
{cameraOn ? 'Camera On' : 'Camera Off'}
</CommonText>
</TouchableOpacity>
)}
</>
)}
</View>
</View>
);
};
const styles = StyleSheet.create({
button: {
padding: 5,
margin: 10,
width: 175,
height: 50,
borderRadius: 10,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'black',
},
localVideo: {
width: 100,
height: 100,
position: 'absolute',
right: 10,
bottom: -50,
},
remoteVideo: {
flex: 1,
position: 'absolute',
left: 0,
top: 0,
margin: 0,
padding: 0,
aspectRatio: 1,
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
overflow: 'hidden',
alignItems: 'center',
},
input: {
height: 40,
width: 150,
borderColor: 'black',
borderWidth: 3,
borderRadius: 10,
margin: 10,
},
});
export default Dialer;
I’ve got 100 tabs open and it’s just getting worse and worse, if someone could walk me through this. I’d really appreciate it.