enable local video view in mobile

This commit is contained in:
balzack 2023-03-29 23:29:53 -07:00
parent 87a6ba4de9
commit 49602436d8
3 changed files with 134 additions and 100 deletions

View File

@ -57,7 +57,16 @@ export function useRingContext() {
urls: 'turn:35.165.123.117:5001?transport=udp',
username: 'user',
credential: 'pass'
}];
}
];
const constraints = {
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true,
VoiceActivityDetection: true
}
};
const updateState = (value) => {
setState((s) => ({ ...s, ...value }))
@ -123,6 +132,44 @@ export function useRingContext() {
ringing.current.set(key, call);
updateState({ ringing: ringing.current });
const impolite = async () => {
if (processing.current) {
return;
}
processing.current = true;
while (offers.current.length > 0) {
descriptions = offers.current;
offers.current = [];
for (let i = 0; i < descriptions.length; i++) {
const description = descriptions[i];
stream.current = null;
if (description == null) {
const offer = await pc.current.createOffer(constraints);
await pc.current.setLocalDescription(offer);
ws.current.send(JSON.stringify({ description: offer }));
}
else {
if (description.type === 'offer' && pc.current.signalingState !== 'stable') {
continue;
}
const offer = new RTCSessionDescription(description);
await pc.current.setRemoteDescription(offer);
if (description.type === 'offer') {
const answer = await pc.current.createAnswer();
await pc.current.setLocalDescription(answer);
ws.current.send(JSON.stringify({ description: answer }));
}
}
}
}
processing.current = false;
}
// connect signal socket
candidates.current = [];
calling.current = { state: "connecting", callId, contactNode, contactToken, host: false };
@ -141,8 +188,9 @@ export function useRingContext() {
pc.current.addEventListener( 'iceconnectionstatechange', event => {
console.log("ICE STATE CHANGE", event);
} );
pc.current.addEventListener( 'negotiationneeded', event => {
console.log("ICE NEGOTIATION", event);
pc.current.addEventListener( 'negotiationneeded', async (ev) => {
offers.current.push(null);
impolite();
} );
pc.current.addEventListener( 'signalingstatechange', event => {
console.log("ICE SIGNALING", event);
@ -161,38 +209,6 @@ export function useRingContext() {
stream.current.addTrack(event.track, stream.current);
} );
const impolite = async () => {
if (processing.current) {
return;
}
processing.current = true;
while (offers.current.length > 0) {
descriptions = offers.current;
offers.current = [];
for (let i = 0; i < descriptions.length; i++) {
const description = descriptions[i];
stream.current = null;
if (description.type === 'offer' && pc.current.signalingState !== 'stable') {
continue;
}
const offer = new RTCSessionDescription(description);
await pc.current.setRemoteDescription(offer);
if (description.type === 'offer') {
const answer = await pc.current.createAnswer();
await pc.current.setLocalDescription(answer);
ws.current.send(JSON.stringify({ description: answer }));
}
}
}
processing.current = false;
}
updateState({ localVideo: false, localAudio: false, localStream: null });
videoTrack.current = false;
@ -204,7 +220,7 @@ export function useRingContext() {
audio: true,
});
accessAudio.current = true;
updateState({ localAudio: true, localStream: stream });
updateState({ localAudio: true });
for (const track of stream.getTracks()) {
if (track.kind === 'audio') {
audioTrack.current = track;
@ -259,21 +275,8 @@ export function useRingContext() {
updateState({ callStatus: "connected" });
ws.current.send(JSON.stringify({ AppToken: calleeToken }))
try {
const constraints = {
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true,
VoiceActivityDetection: true
}
};
const offer = await pc.current.createOffer(constraints);
await pc.current.setLocalDescription(offer);
ws.current.send(JSON.stringify({ description: offer }));
}
catch(err) {
console.log(err);
}
offers.current.push(null);
impolite();
}
ws.current.error = (e) => {
console.log(e)
@ -313,6 +316,45 @@ export function useRingContext() {
throw new Error("active session");
}
const polite = async () => {
if (processing.current) {
return;
}
processing.current = true;
while (offers.current.length > 0) {
descriptions = offers.current;
offers.current = [];
for (let i = 0; i < descriptions.length; i++) {
const description = descriptions[i];
stream.current = null;
if (description == null) {
const offer = await pc.current.createOffer(constraints);
await pc.current.setLocalDescription(offer);
ws.current.send(JSON.stringify({ description: offer }));
}
else {
if (description.type === 'offer' && pc.current.signalingState !== 'stable') {
const rollback = new RTCSessionDescription({ type: "rollback" });
await pc.current.setLocalDescription(reollback);
}
const offer = new RTCSessionDescription(description);
await pc.current.setRemoteDescription(offer);
if (description.type === 'offer') {
const answer = await pc.current.createAnswer();
await pc.current.setLocalDescription(answer);
ws.current.send(JSON.stringify({ description: answer }));
}
}
}
}
processing.current = false;
}
// create call
const { server, token } = access.current;
const call = await addCall(server, token, cardId);
@ -360,7 +402,8 @@ export function useRingContext() {
console.log("ICE STATE CHANGE", event);
} );
pc.current.addEventListener( 'negotiationneeded', event => {
console.log("ICE NEGOTIATION", event);
offers.current.push(null);
polite();
} );
pc.current.addEventListener( 'signalingstatechange', event => {
console.log("ICE SIGNALING", event);
@ -403,38 +446,6 @@ export function useRingContext() {
console.log(err);
}
const polite = async () => {
if (processing.current) {
return;
}
processing.current = true;
while (offers.current.length > 0) {
descriptions = offers.current;
offers.current = [];
for (let i = 0; i < descriptions.length; i++) {
const description = descriptions[i];
stream.current = null;
if (description.type === 'offer' && pc.current.signalingState !== 'stable') {
const rollback = new RTCSessionDescription({ type: "rollback" });
await pc.current.setLocalDescription(reollback);
}
const offer = new RTCSessionDescription(description);
await pc.current.setRemoteDescription(offer);
if (description.type === 'offer') {
const answer = await pc.current.createAnswer();
await pc.current.setLocalDescription(answer);
ws.current.send(JSON.stringify({ description: answer }));
}
}
}
processing.current = false;
}
ws.current = createWebsocket(`wss://${server}/signal`);
ws.current.onmessage = async (ev) => {
// handle messages [polite]
@ -494,8 +505,11 @@ export function useRingContext() {
enableVideo: async () => {
if (!accessVideo.current) {
const stream = await mediaDevices.getUserMedia({
video: true,
audio: true,
video: {
frameRate: 30,
facingMode: 'user'
}
});
accessVideo.current = true;
accessAudio.current = true;

View File

@ -187,6 +187,11 @@ export function Session() {
console.log(state.remoteStream);
}, [state.remoteStream]);
useEffect(() => {
console.log("**** LOCAL ****");
console.log(state.localStream, state.localVideo);
}, [state.localStream, state.localVideo]);
const HomeScreen = ({ navParams }) => {
const conversation = useContext(ConversationContext);
@ -462,24 +467,33 @@ export function Session() {
<Logo src={state.callLogo} width={callWidth} height={callHeight} radius={4} />
</View>
)}
{ state.localStream && (
<RTCView
style={styles.callLocal}
mirror={true}
objectFit={'contain'}
streamURL={state.localStream.toURL()}
zOrder={0}
/>
)}
<View style={styles.callOptions}>
{ !state.localVideo && (
<TouchableOpacity style={styles.callOption} onPress={actions.enableVideo}>
{ state.localVideo && (
<TouchableOpacity style={styles.callOption} onPress={actions.disableVideo}>
<MatIcons name={'video-outline'} size={20} color={Colors.white} />
</TouchableOpacity>
)}
{ state.localVideo && (
<TouchableOpacity style={styles.callOption} onPress={actions.disableVideo}>
{ !state.localVideo && (
<TouchableOpacity style={styles.callOption} onPress={actions.enableVideo}>
<MatIcons name={'video-off-outline'} size={20} color={Colors.white} />
</TouchableOpacity>
)}
{ !state.localAudio && (
<TouchableOpacity style={styles.callOption} onPress={actions.enableVideo}>
{ state.localAudio && (
<TouchableOpacity style={styles.callOption} onPress={actions.disableAudio}>
<MatIcons name={'microphone'} size={20} color={Colors.white} />
</TouchableOpacity>
)}
{ state.localAudio && (
<TouchableOpacity style={styles.callOption} onPress={actions.disableVideo}>
{ !state.localAudio && (
<TouchableOpacity style={styles.callOption} onPress={actions.enableAudio}>
<MatIcons name={'microphone-off'} size={20} color={Colors.white} />
</TouchableOpacity>
)}

View File

@ -204,10 +204,10 @@ export const styles = StyleSheet.create({
callEnd: {
position: 'absolute',
bottom: 16,
borderRadius: 16,
borderRadius: 24,
borderColor: Colors.white,
borderWidth: 1,
padding: 4,
padding: 8,
backgroundColor: Colors.alert,
},
callLogo: {
@ -222,18 +222,24 @@ export const styles = StyleSheet.create({
top: 16,
},
callOption: {
borderRadius: 16,
borderRadius: 24,
borderColor: Colors.white,
borderWidth: 1,
padding: 4,
padding: 8,
backgroundColor: Colors.primary,
marginLeft: 8,
marginRight: 8,
marginLeft: 16,
marginRight: 16,
},
callRemote: {
width: '100%',
height: '100%',
},
callLocal: {
position: 'absolute',
bottom: 16,
left: 16,
height: '33%',
width: '33%',
},
});