updating call screen layout

This commit is contained in:
balzack 2025-01-27 22:36:23 -08:00
parent 7efd88f272
commit ff3ad5d396
3 changed files with 82 additions and 27 deletions

View File

@ -74,4 +74,17 @@ export const styles = StyleSheet.create({
paddingTop: 8,
gap: 32,
},
box: {
position: 'absolute',
top: 0,
right: 16,
width: '20%',
height: '20%',
},
full: {
position: 'absolute',
width: '100%',
height: '100%',
backgroundColor: 'rgb(64,64,64)',
},
});

View File

@ -9,6 +9,7 @@ import { ActivityIndicator } from 'react-native-paper';
import FastImage from 'react-native-fast-image'
import LinearGradient from 'react-native-linear-gradient';
import { Colors } from '../constants/Colors';
import { RTCView } from 'react-native-webrtc';
export function Calling({ callCard }: { callCard: string }) {
const { state, actions } = useCalling();
@ -117,14 +118,12 @@ export function Calling({ callCard }: { callCard: string }) {
/>
{ state.loaded && (
<LinearGradient style={{...styles.overlap, width: '100%', height: frameHeight / 2, top: 2, borderRadius: 8}} start={{x: 0, y: 0}} end={{x: 0, y: 0.5}} colors={['rgba(64,64,64,1)', 'rgba(64,64,64, 0)']}>
<LinearGradient style={{...styles.overlap, width: '100%', height: frameHeight / 2, top: 2, borderRadius: 8}} start={{x: 0, y: 0}} end={{x: 0, y: 0.5}} colors={['rgba(64,64,64,1)', 'rgba(64,64,64, 0)']}>
</LinearGradient>
<LinearGradient style={{...styles.overlap, width: '100%', height: frameHeight / 2, top: 2, borderRadius: 8}} start={{x: 0, y: 0}} end={{x: 0, y: 0.5}} colors={['rgba(64,64,64,1)', 'rgba(64,64,64, 0)']} />
</LinearGradient>
)}
{ state.loaded && (
<LinearGradient style={{...styles.overlap, width: '100%', height: frameHeight / 2, bottom: 2, borderRadius: 8}} start={{x: 0, y: 0.5}} end={{x: 0, y: 1}} colors={['rgba(64,64,64,0)', 'rgba(64,64,64, 1)']}>
<LinearGradient style={{...styles.overlap, width: '100%', height: frameHeight / 2, bottom: 2, borderRadius: 8}} start={{x: 0, y: 0.5}} end={{x: 0, y: 1}} colors={['rgba(64,64,64,0)', 'rgba(64,64,64, 1)']}>
</LinearGradient>
<LinearGradient style={{...styles.overlap, width: '100%', height: frameHeight / 2, bottom: 2, borderRadius: 8}} start={{x: 0, y: 0.5}} end={{x: 0, y: 1}} colors={['rgba(64,64,64,0)', 'rgba(64,64,64, 1)']} />
</LinearGradient>
)}
{ state.loaded && (
@ -145,6 +144,33 @@ export function Calling({ callCard }: { callCard: string }) {
)}
</View>
)}
{ state.calling && state.loaded && state.remote && (
<RTCView
style={styles.full}
mirror={true}
objectFit={'contain'}
streamURL={state.remote.toURL()}
zOrder={2}
/>
)}
{ state.calling && state.loaded && state.local && !state.remote && (
<RTCView
style={styles.full}
mirror={true}
objectFit={'contain'}
streamURL={state.local.toURL()}
zOrder={2}
/>
)}
{ state.calling && state.loaded && state.local && state.remote && (
<RTCView
style={styles.box}
mirror={true}
objectFit={'contain'}
streamURL={state.local.toURL()}
zOrder={2}
/>
)}
{ state.calling && state.loaded && (
<View style={{ ...styles.overlap, bottom: frameOffset }}>
<View style={{ paddingTop: 8, paddingBottom: 8, paddingLeft: 16, paddingRight: 16, gap: 16, display: 'flex', flexDirection: 'row', borderRadius: 16, backgroundColor: 'rgba(128,128,128,0.5)' }}>

View File

@ -11,7 +11,7 @@ import {
RTCSessionDescription,
RTCView,
MediaStream,
MediaStreamTrack,
MediaiStreamTrack,
mediaDevices,
registerGlobals
} from 'react-native-webrtc';
@ -20,6 +20,8 @@ export function useCalling() {
const app = useContext(AppContext) as ContextType;
const display = useContext(DisplayContext) as ContextType;
const call = useRef(null as { policy: string, peer: RTCPeerConnection, link: Link, candidates: RTCIceCandidate[] } | null);
const localStream = useRef(null);
const remoteStream = useRef(null);
const [state, setState] = useState({
strings: {},
ringing: [],
@ -29,7 +31,8 @@ export function useCalling() {
failed: false,
loaded: false,
panelOffset: 0,
stream: null,
local: null,
remote: null,
audio: null,
audioEnabled: false,
video: null,
@ -67,23 +70,24 @@ export function useCalling() {
const { policy, peer, link } = call.current;
if (status === 'connected') {
try {
const stream = await mediaDevices.getUserMedia({
remoteStream.current = new MediaStream();
localStream.current = await mediaDevices.getUserMedia({
audio: true,
video: {
frameRate: 30,
facingMode: 'user'
}
});
const audio = stream.getTracks().find(track => track.kind === 'audio');
const video = stream.getTracks().find(track => track.kind === 'video');
const audio = localStream.current.getTracks().find(track => track.kind === 'audio');
const video = localStream.current.getTracks().find(track => track.kind === 'video');
if (audio) {
audio.enabled = true;
peer.addTrack(audio, stream);
peer.addTrack(audio, localStream.current);
}
if (video) {
video.enabled = false;
}
updateState({ audio, video, stream, audioAdded: true, audioEnabled: true, videoAdded: false, videoEnabled: false });
updateState({ audio, video, audioAdded: true, audioEnabled: true, videoAdded: false, videoEnabled: false });
} catch (err) {
console.log(err);
updateState({ failed: true });
@ -96,32 +100,30 @@ export function useCalling() {
console.log(err);
}
call.current = null;
updateState({ calling: null, failed: false, audio: null, video: null });
localStream.current = null;
remoteStream.current = null,
updateState({ calling: null, failed: false, audio: null, video: null, local: null, remote: null });
}
}
}
const linkMessage = async (message: any) => {
console.log("LINK MSG", message);
if (call.current) {
const { peer, link, candidates, policy } = call.current;
try {
if (message.description) {
if (message.description.type === 'offer' && peer.signalingState !== 'stable') {
if (policy === 'polite') {
const rollback = new RTCSessionDescription({ type: 'rollback' });
await peer.setLocalDescription(rollback);
} else {
return;
}
}
const offer = new RTCSessionDescription(message.description);
await peer.setRemoteDescription(offer);
console.log("SET REMOTE!!!");
if (message.description.type === 'offer') {
console.log("RESPOND OFFER");
const description = await peer.createAnswer();
await peer.setLocalDescription(description);
link.sendMessage({ description });
}
call.current.candidates = [];
for (const candidate of candidates) {
await peer.addIceCandidate(candidate);
};
@ -142,6 +144,7 @@ export function useCalling() {
}
const peerCandidate = async (candidate) => {
console.log("PEER CANDIDATE");
if (call.current && candidate) {
const { link } = call.current;
await link.sendMessage({ candidate });
@ -149,11 +152,16 @@ export function useCalling() {
}
const peerNegotiate = async () => {
console.log("PEER NEGOTIATE");
if (call.current) {
const { peer, link } = call.current;
const description = await peer.createOffer(constraints);
await peer.setLocalDescription(description);
await link.sendMessage({ description });
try {
const { peer, link } = call.current;
const description = await peer.createOffer(constraints);
await peer.setLocalDescription(description);
await link.sendMessage({ description });
} catch (err) {
console.log(err);
}
}
}
@ -178,7 +186,10 @@ export function useCalling() {
console.log("ICE SIGNALING", event);
});
peerConnection.addEventListener( 'track', event => {
console.log("TRACK EVENT");
remoteStream.current.addTrack(event.track, remoteStream.current);
if (event.track.kind === 'video') {
updateState({ remote: remoteStream.current });
}
});
return peerConnection;
}
@ -215,7 +226,9 @@ export function useCalling() {
console.log(err);
}
call.current = null;
updateState({ calling: null, audio: null, video: null });
localStream.current = null;
remoteStream.current = null;
updateState({ calling: null, audio: null, video: null, local: null, remote: null });
},
accept: async (callId: string, call: Call) => {
if (call.current) {
@ -279,7 +292,10 @@ export function useCalling() {
throw new Error('cannot start video');
}
if (!state.videoAdded) {
call.current.peer.addTrack(state.video, state.stream);
call.current.peer.addTrack(state.video, localStream.current);
const local = new MediaStream();
local.addTrack(state.video, local);
updateState({ local });
}
state.video.enabled = true;
updateState({ videoAdded: true, videoEnabled: true });