Skip to content

Commit

Permalink
feat(app): create basic webrtc protocol for video call
Browse files Browse the repository at this point in the history
  • Loading branch information
chukitipok authored and Mikadows committed Jun 29, 2022
1 parent 642ed17 commit 646ee6f
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Orders from './components/Order/Orders';
import Profile from './components/Profile/Profile';
import Privacy from './components/Privacy';
import ResetPassword from './components/Authentication/ResetPassword';
import {Streaming} from "./components/Streaming/Streaming";

function App() {
const queryClient = new QueryClient();
Expand All @@ -40,6 +41,7 @@ function App() {
<Route path="/privacy" element={<Privacy />} />
<Route path="/reset-password/:token" element={<ResetPassword />} />
<Route path="*" element={<NotFound />} />
<Route path="/streaming" element={<Streaming />} />
</Routes>
</Router>
<ReactQueryDevtools initialIsOpen={false} />
Expand Down
42 changes: 42 additions & 0 deletions src/assets/css/streaming.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.web-rtc-page {
color: white;
background: #282c34;
padding: 20px;
text-align: center;
button {
display: block;
margin: 0 auto;
padding: 10px 25px;
border-radius: 10px;
cursor: pointer;
font-size: 20px;
}
.video-container {
display: flex;
justify-content: center;
.video-block {
height: 200px;
width: 300px;
}
}
}

.loader {
width: 90px;
height: 90px;
border-radius: 50%;
margin: 0 auto 10px auto;
position: relative;
border: 10px solid rgba(255, 255, 255, 0.2);
border-top: 10px solid #ffffff;
animation: spin 1s infinite linear;
}

@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
87 changes: 87 additions & 0 deletions src/components/Streaming/Streaming.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React, { useEffect, useMemo, useRef, useState } from 'react';
import 'react-responsive-carousel/lib/styles/carousel.min.css';
import SimplePeer, { Instance, SignalData } from 'simple-peer';
import '../../assets/css/_carousel.css';
import '../../assets/css/streaming.scss';

enum ConnectionStatus {
OFFERING,
RECEIVING,
CONNECTED,
}

// const webSocketConnection = new WebSocket(process.env.REACT_APP_WEBSOCKET_API_ENDPOINT);

export const Streaming = () => {
const websocketEndpoint = process.env.REACT_APP_WEBSOCKET_API_ENDPOINT;
const webSocketConnection = useMemo(
() => new WebSocket(websocketEndpoint ? websocketEndpoint : ''),
[websocketEndpoint],
);
const videoSelf = useRef<HTMLVideoElement | null>(null);
const videoCaller = useRef<HTMLVideoElement | null>(null);
const [connectionStatus, setConnectionStatus] =
useState<ConnectionStatus | null>(null);
const [offerSignal, setOfferSignal] = useState<SignalData>();
const [simplePeer, setSimplePeer] = useState<Instance>();

useEffect(() => {
webSocketConnection.onmessage = (message: any) => {
const payload = JSON.parse(message.data);
if (payload?.type === 'offer') {
setOfferSignal(payload);
setConnectionStatus(ConnectionStatus.RECEIVING);
} else if (payload?.type === 'answer') simplePeer?.signal(payload);
};
}, [simplePeer, webSocketConnection]);

const sendOrAcceptInvitation = (isInitiator: boolean, offer?: SignalData) => {
navigator.mediaDevices
.getUserMedia({ video: true, audio: false })
.then(async (mediaStream) => {
const video = videoSelf.current;
video!.srcObject = mediaStream;
await video!.play();

const sp = new SimplePeer({
trickle: false,
initiator: isInitiator,
stream: mediaStream,
});

if (isInitiator) setConnectionStatus(ConnectionStatus.OFFERING);
else offer && sp.signal(offer);

sp.on('signal', (data) =>
webSocketConnection.send(JSON.stringify(data)),
);
sp.on('connect', () => setConnectionStatus(ConnectionStatus.CONNECTED));
sp.on('stream', async (stream) => {
const video = videoCaller.current;
video!.srcObject = stream;
await video!.play();
});
setSimplePeer(sp);
});
};

return (
<div className="web-rtc-page">
{connectionStatus === null && (
<button onClick={() => sendOrAcceptInvitation(true)}>CALL</button>
)}
{connectionStatus === ConnectionStatus.OFFERING && (
<div className="loader"></div>
)}
{connectionStatus === ConnectionStatus.RECEIVING && (
<button onClick={() => sendOrAcceptInvitation(false, offerSignal)}>
ANSWER CALL
</button>
)}
<div className="video-container">
<video ref={videoSelf} className="video-block" />
<video ref={videoCaller} className="video-block" />
</div>
</div>
);
};

0 comments on commit 646ee6f

Please sign in to comment.