Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic working video #1

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 49 additions & 12 deletions src/components/webRTCpoc.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react';

Check failure on line 1 in src/components/webRTCpoc.tsx

View workflow job for this annotation

GitHub Actions / lint

There should be no empty line within import group

import {Text} from 'react-native';

import {MediaStream, RTCPeerConnection, RTCView} from 'react-native-webrtc';

import {API_BASE} from '@env';
Expand All @@ -16,6 +18,8 @@
const cameraURL =
API_BASE.replace('http', 'ws') + '/live/webrtc/api/ws?src=' + cameraName;

const [reload, setReload] = React.useState<boolean>(false);
const [loading, setLoading] = React.useState<boolean>(true);
const [remoteStream, setRemoteStream] = React.useState<MediaStream | null>(
null,
);
Expand All @@ -26,11 +30,20 @@
const pcRef = React.useRef<RTCPeerConnection | null>(null);
const wsRef = React.useRef<WebSocket | null>(null);

function onIceConnect() {
if (pcRef?.current?.iceConnectionState === 'connected') {
setLoading(false);
}
}

const connect = React.useCallback(async (url: string) => {
setLoading(true);
pcRef.current = new RTCPeerConnection(webRTCconfig);
wsRef.current = new WebSocket(url);

const pc = pcRef.current;
// add this before connecting to websocket to ensure it is always captured.
pcRef.current.addEventListener('iceconnectionstatechange', onIceConnect);

wsRef.current = new WebSocket(url);
const ws = wsRef.current;

const tracks = [
Expand All @@ -45,26 +58,24 @@

setLocalStream(new MediaStream(tracks));

pc.addEventListener('track', (event: any) => {
const remoteMediaStream = new MediaStream(undefined);

pc.addEventListener('track', async (event: any) => {

Check warning on line 63 in src/components/webRTCpoc.tsx

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
// Grab the remote track from the connected participant.
const track = event?.track;
if (track) {
const remoteMediaStream = new MediaStream(undefined);
console.log(
'🪵 | file: webRTCpoc.tsx:58 | ws.addEventListener | track:',
track,
);
remoteMediaStream.addTrack(event.track);
setRemoteStream(remoteMediaStream);
}
});

ws.addEventListener('open', async () => {
pc.addEventListener('icecandidate', (ev: any) => {

Check warning on line 73 in src/components/webRTCpoc.tsx

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
//? This is where we send the new icecandidate info to the server
if (!ev.candidate) {
return;
}

const msg = {
type: 'webrtc/candidate',
value: ev.candidate.candidate,
Expand All @@ -91,34 +102,60 @@
pc.setRemoteDescription({type: 'answer', sdp: msg.value});
}
});

// the following is to ensure that ice connection eventually becomes connected or completed
// as it can get stuck in other states which are an error state
let attempts = 0;
while (
pc.iceConnectionState !== 'connected' &&
pc.iceConnectionState !== 'completed'
) {
// async timeout for 100ms
await new Promise(resolve => setTimeout(resolve, 100));
attempts++;

if (attempts > 5) {
throw new Error('Could not connect');
}
}

// we no longer want to listen to connected state change events
pc.removeEventListener('iceconnectedstatechange', onIceConnect);
}, []);

React.useEffect(() => {
if (cameraURL && cameraName) {
connect(cameraURL);
connect(cameraURL).catch(() => {
// toggle the reload value on error so this useEffect will run again
setReload(!reload);
});
}

return () => {
remoteStream?.getTracks().forEach(t => t.stop());
remoteStream?.release();
remoteStream?.release(true);
localStream?.getTracks().forEach(t => t.stop());
localStream?.release();
pcRef?.current?.close();
};
}, [cameraURL, cameraName]);
}, [cameraURL, cameraName, reload]);

Check warning on line 141 in src/components/webRTCpoc.tsx

View workflow job for this annotation

GitHub Actions / lint

React Hook React.useEffect has missing dependencies: 'connect', 'localStream', and 'remoteStream'. Either include them or remove the dependency array

if (!cameraName) {
return null;
}

if (loading) {
return <Text>Loading ...</Text>;
}

if (remoteStream) {
return (
<RTCView
style={{width: '100%', height: '100%'}}

Check warning on line 154 in src/components/webRTCpoc.tsx

View workflow job for this annotation

GitHub Actions / lint

Inline style: { width: '100%', height: '100%' }
objectFit={'contain'}
streamURL={remoteStream.toURL()}
/>
);
}
return null;
return <Text>No video stream set</Text>;
};
2 changes: 1 addition & 1 deletion src/screens/homeScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const HomeScreen = () => {
{currentCamera && (
<BaseView className="flex-1">
<WebRTCPOC cameraName={currentCamera} />
<BaseText>Vieweing: {currentCamera}</BaseText>
<BaseText>Viewing: {currentCamera}</BaseText>
</BaseView>
)}
</BaseView>
Expand Down
Loading