using configured ice server

This commit is contained in:
Roland Osborne 2023-04-13 15:11:33 -07:00
parent dd34a17268
commit f8dd0ea5e8
10 changed files with 94 additions and 40 deletions

View File

@ -181,8 +181,8 @@ export function useAppContext() {
card.actions.setRevision(cardRev);
}
if (activity.ring) {
const { cardId, callId, calleeToken } = activity.ring;
ring.actions.ring(cardId, callId, calleeToken);
const { cardId, callId, calleeToken, iceUrl, iceUsername, icePassword } = activity.ring;
ring.actions.ring(cardId, callId, calleeToken, iceUrl, iceUsername, icePassword);
}
}
catch (err) {

View File

@ -49,14 +49,6 @@ export function useRingContext() {
const connected = useRef(false);
const candidates = useRef([]);
const iceServers = [
{
urls: 'turn:44.238.207.157:3478?transport=udp',
username: 'user',
credential: 'pass'
},
];
const constraints = {
mandatory: {
OfferToReceiveAudio: true,
@ -168,9 +160,9 @@ export function useRingContext() {
processing.current = false;
}
const transmit = async (policy) => {
const transmit = async (policy, ice) => {
pc.current = new RTCPeerConnection({ iceServers });
pc.current = new RTCPeerConnection({ iceServers: ice });
pc.current.addEventListener( 'connectionstatechange', event => {
console.log("CONNECTION STATE", event);
} );
@ -234,7 +226,7 @@ export function useRingContext() {
}
}
const connect = async (policy, node, token, clearRing, clearAlive) => {
const connect = async (policy, node, token, clearRing, clearAlive, ice) => {
// connect signal socket
connected.current = false;
@ -256,7 +248,7 @@ export function useRingContext() {
if (policy === 'polite') {
connected.current = true;
InCallManager.start({media: 'audio'});
transmit('polite');
transmit('polite', ice);
polite();
}
}
@ -311,7 +303,7 @@ export function useRingContext() {
if (policy === 'impolite') {
connected.current = true;
InCallManager.start({media: 'audio'});
transmit('impolite');
transmit('impolite', ice);
impolite();
}
}
@ -335,9 +327,9 @@ export function useRingContext() {
clearSession: () => {
access.current = null;
},
ring: (cardId, callId, calleeToken) => {
ring: (cardId, callId, calleeToken, iceUrl, iceUsername, icePassword) => {
const key = `${cardId}:${callId}`
const call = ringing.current.get(key) || { cardId, calleeToken, callId }
const call = ringing.current.get(key) || { cardId, calleeToken, callId, iceUrl, iceUsername, icePassword }
call.expires = Date.now() + EXPIRE;
ringing.current.set(key, call);
updateState({ ringing: ringing.current });
@ -369,7 +361,7 @@ export function useRingContext() {
}
}
},
accept: async (cardId, callId, contactNode, contactToken, calleeToken) => {
accept: async (cardId, callId, contactNode, contactToken, calleeToken, iceUrl, iceUsername, icePassword) => {
if (calling.current) {
throw new Error("active session");
}
@ -382,7 +374,8 @@ export function useRingContext() {
updateState({ ringing: ringing.current, callStatus: "connecting", cardId });
calling.current = { callId, contactNode, contactToken, host: false };
await connect('impolite', contactNode, calleeToken, () => {}, () => {});
const ice = [{ urls: iceUrl, username: iceUsername, credential: icePassword }];
await connect('impolite', contactNode, calleeToken, () => {}, () => {}, ice);
}
},
end: async () => {
@ -412,9 +405,9 @@ export function useRingContext() {
// create call
const { server, token } = access.current;
const call = await addCall(server, token, cardId);
const { id, keepAlive, callerToken, calleeToken } = call;
const { id, keepAlive, callerToken, calleeToken, iceUrl, iceUsername, icePassword } = call;
try {
await addContactRing(contactNode, contactToken, { index, callId: id, calleeToken });
await addContactRing(contactNode, contactToken, { index, callId: id, calleeToken, iceUrl, iceUsername, icePassword });
}
catch (err) {
console.log(err);
@ -436,7 +429,7 @@ export function useRingContext() {
}
}
else {
await addContactRing(contactNode, contactToken, { index, callId: id, calleeToken });
await addContactRing(contactNode, contactToken, { index, callId: id, calleeToken, iceUrl, iceUsername, icePassword });
index += 1;
}
}
@ -447,7 +440,8 @@ export function useRingContext() {
updateState({ callStatus: "ringing", cardId });
calling.current = { callId: id, host: true };
await connect('polite', server, callerToken, () => clearInterval(ringInterval), () => clearInterval(aliveInterval));
const ice = [{ urls: iceUrl, username: iceUsername, credential: icePassword }];
await connect('polite', server, callerToken, () => clearInterval(ringInterval), () => clearInterval(aliveInterval), ice);
},
enableVideo: async () => {
if (!videoTrack.current) {

View File

@ -191,6 +191,8 @@ export function Dashboard(props) {
onValueChange={actions.setPushSupported} trackColor={styles.track}/>
</TouchableOpacity>
<View style={styles.label}></View>
<TouchableOpacity style={styles.media} activeOpacity={1}
onPress={() => actions.setEnableImage(!state.enableImage)}>
<Text style={styles.modalLabel}>Enable Image Queue: </Text>
@ -209,6 +211,21 @@ export function Dashboard(props) {
<Switch style={styles.switch} value={state.enableVideo}
onValueChange={actions.setEnableVideo} trackColor={styles.track}/>
</TouchableOpacity>
<View style={styles.label}></View>
<TouchableOpacity style={styles.ice} activeOpacity={1}
onPress={() => actions.setEnableIce(!state.enableIce)}>
<Text style={styles.modalLabel}>Enable WebRTC Calls: </Text>
<Switch style={styles.switch} value={state.enableIce}
onValueChange={actions.setEnableIce} trackColor={styles.track}/>
</TouchableOpacity>
<TextInput style={styles.input} value={state.iceUrl} onChangeText={actions.setIceUrl}
editable={state.enableIce} autoCorrect={false} autoCapitalize="none" placeholder="Relay URL" />
<TextInput style={styles.input} value={state.iceUsername} onChangeText={actions.setIceUsername}
editable={state.enableIce} autoCorrect={false} autoCapitalize="none" placeholder="Relay Username" />
<TextInput style={styles.input} value={state.icePassword} onChangeText={actions.setIcePassword}
editable={state.enableIce} autoCorrect={false} autoCapitalize="none" placeholder="Relay Password" />
</View>
<View style={styles.modalControls}>
<TouchableOpacity style={styles.cancel} onPress={actions.hideEditConfig}>

View File

@ -194,7 +194,7 @@ export const styles = StyleSheet.create({
padding: 4,
borderRadius: 4,
marginBottom: 16,
fontSize: 16,
fontSize: 12,
color: Colors.text,
},
switch: {
@ -224,4 +224,20 @@ export const styles = StyleSheet.create({
borderRadius: 4,
borderColor: Colors.divider,
},
label: {
borderTopWidth: 1,
borderColor: Colors.divider,
marginTop: 12,
},
labelText: {
fontSize: 14,
color: Colors.text,
},
ice: {
display: 'flex',
flexDirection: 'row',
marginTop: 8,
alignItems: 'center',
paddingBottom: 8,
}
});

View File

@ -28,6 +28,10 @@ export function useDashboard(config, server, token) {
enableAudio: true,
enableVideo: true,
createToken: null,
enableIce: false,
iceUrl: null,
iceUsername: null,
icePassword: null,
});
const navigate = useNavigate();
@ -55,8 +59,8 @@ export function useDashboard(config, server, token) {
};
useEffect(() => {
const { keyType, accountStorage, domain, enableImage, enableAudio, enableVideo, pushSupported } = config;
updateState({ keyType, storage: accountStorage.toString(), domain, enableImage, enableAudio, enableVideo, pushSupported });
const { keyType, accountStorage, domain, enableImage, enableAudio, enableVideo, pushSupported, enableIce, iceUrl, iceUsername, icePassword } = config;
updateState({ keyType, storage: accountStorage.toString(), domain, enableImage, enableAudio, enableVideo, pushSupported, enableIce, iceUrl, iceUsername, icePassword });
}, [config]);
useEffect(() => {
@ -111,9 +115,21 @@ export function useDashboard(config, server, token) {
setKeyType: (keyType) => {
updateState({ keyType });
},
setEnableIce: (enableIce) => {
updateState({ enableIce });
},
setIceUrl: (iceUrl) => {
updateState({ iceUrl });
},
setIceUsername: (iceUsername) => {
updateState({ iceUsername });
},
setIcePassword: (icePassword) => {
updateState({ icePassword });
},
saveConfig: async () => {
const { storage, domain, keyType, enableImage, enableAudio, enableVideo } = state;
const config = { accountStorage: Number(storage), domain, keyType, enableImage, enableAudio, enableVideo };
const { storage, domain, keyType, enableImage, enableAudio, enableVideo, enableIce, iceUrl, iceUsername, icePassword } = state;
const config = { accountStorage: Number(storage), domain, keyType, enableImage, enableAudio, enableVideo, enableIce, iceUrl, iceUsername, icePassword };
await setNodeConfig(server, token, config);
},
enableUser: async (accountId, enabled) => {

View File

@ -329,7 +329,8 @@ export function Session() {
useEffect(() => {
let incoming = [];
for (let i = 0; i < state.ringing.length; i++) {
const { img, name, handle, callId, cardId, contactNode, contactToken, calleeToken } = state.ringing[i];
const call = state.ringing[i];
const { img, cardId, callId, name, handle, contactNode } = call || {};
const label = name ? name : `${handle}@${contactNode}`;
const key = `${cardId}:${callId}`
incoming.push(
@ -339,10 +340,10 @@ export function Session() {
<TouchableOpacity style={styles.ringIgnore} onPress={() => actions.ignore({ cardId, callId })}>
<MatIcons name={'eye-off-outline'} size={20} color={Colors.text} />
</TouchableOpacity>
<TouchableOpacity style={styles.ringDecline} onPress={() => actions.decline({ cardId, contactNode, contactToken, callId })}>
<TouchableOpacity style={styles.ringDecline} onPress={() => actions.decline(call)}>
<MatIcons name={'phone-hangup'} size={20} color={Colors.alert} />
</TouchableOpacity>
<TouchableOpacity style={styles.ringAccept} onPress={() => actions.accept({ cardId, callId, contactNode, contactToken, calleeToken })}>
<TouchableOpacity style={styles.ringAccept} onPress={() => actions.accept(call)}>
<MatIcons name={'phone'} size={20} color={Colors.primary} />
</TouchableOpacity>
</View>

View File

@ -66,7 +66,7 @@ export function CardsBody({ filter, sort, openContact, addChannel }) {
data={state.cards}
initialNumToRender={25}
renderItem={({ item }) => <CardItem item={item} openContact={openContact}
call={() => call(item)} message={() => addChannel(item.cardId)} />}
enableIce={state.enableIce} call={() => call(item)} message={() => addChannel(item.cardId)} />}
keyExtractor={item => item.cardId}
/>
)}

View File

@ -4,7 +4,7 @@ import { styles } from './CardItem.styled';
import MatIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import Colors from 'constants/Colors';
export function CardItem({ item, openContact, call, message }) {
export function CardItem({ item, openContact, enableIce, call, message }) {
const select = () => {
const { guid, name, handle, node, location, description, imageSet } = item;
@ -26,9 +26,11 @@ export function CardItem({ item, openContact, call, message }) {
<TouchableOpacity style={styles.option} onPress={message}>
<MatIcons name={'message-outline'} size={20} color={Colors.primary} />
</TouchableOpacity>
{ enableIce && (
<TouchableOpacity style={styles.option} onPress={call}>
<MatIcons name={'phone-outline'} size={20} color={Colors.primary} />
</TouchableOpacity>
)}
</View>
)}
{ item.status === 'connected' && item.offsync === 1 && (

View File

@ -1,13 +1,16 @@
import { useState, useEffect, useRef, useContext } from 'react';
import { CardContext } from 'context/CardContext';
import { RingContext } from 'context/RingContext';
import { AccountContext } from 'context/AccountContext';
export function useCards(filter, sort) {
const [state, setState] = useState({
cards: [],
enableIce: false,
});
const account = useContext(AccountContext);
const card = useContext(CardContext);
const ring = useContext(RingContext);
@ -15,6 +18,11 @@ export function useCards(filter, sort) {
setState((s) => ({ ...s, ...value }));
}
useEffect(() => {
const { enableIce } = account.state.status || {};
updateState({ enableIce });
}, [account.state]);
const setCardItem = (item) => {
const { profile, detail, cardId } = item.card || { profile: {}, detail: {} }
const { name, handle, node, guid, location, description, imageSet } = profile;

View File

@ -44,14 +44,14 @@ export function useSession() {
const expired = Date.now();
ring.state.ringing.forEach(call => {
if (call.expires > expired && !call.status) {
const { callId, cardId, calleeToken } = call;
const { callId, cardId, calleeToken, iceUrl, iceUsername, icePassword } = call;
const contact = card.state.cards.get(cardId);
if (contact) {
const { imageSet, name, handle, node, guid } = contact.card?.profile || {};
const { token } = contact.card?.detail || {};
const contactToken = `${guid}.${token}`;
const img = imageSet ? card.actions.getCardImageUrl(cardId) : null;
ringing.push({ cardId, img, name, handle, contactNode: node, callId, contactToken, calleeToken });
ringing.push({ cardId, img, name, handle, contactNode: node, callId, contactToken, calleeToken, iceUrl, iceUsername, icePassword });
}
}
});
@ -106,8 +106,8 @@ export function useSession() {
await ring.actions.decline(cardId, contactNode, contactToken, callId);
},
accept: async (call) => {
const { cardId, callId, contactNode, contactToken, calleeToken } = call;
await ring.actions.accept(cardId, callId, contactNode, contactToken, calleeToken);
const { cardId, callId, contactNode, contactToken, calleeToken, iceUrl, iceUsername, icePassword } = call;
await ring.actions.accept(cardId, callId, contactNode, contactToken, calleeToken, iceUrl, iceUsername, icePassword);
},
end: async () => {
await ring.actions.end();