{"id":28026,"date":"2022-08-09T08:10:14","date_gmt":"2022-08-09T08:10:14","guid":{"rendered":"http:\/\/stream-videos-with-webrtc-api-and-react"},"modified":"2025-02-08T11:27:19","modified_gmt":"2025-02-08T19:27:19","slug":"stream-videos-with-webrtc-api-and-react","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/","title":{"rendered":"Stream Videos with WebRTC API and React"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>Few years ago, when COVID-19 hit the world, we depended on video conferencing software such as Zoom, and Google Meet for remote work. One technology that makes video conferencing on the web possible is WebRTC. In this article, we\u2019ll be learning what WebRTC is, how it works, and we will be building a basic video chat app using Reactjs.<\/p>\n<h2>What is WebRTC<\/h2>\n<p>WebRTC (stands for Web Real Time Connection) is a technology that that allows you to create peer to peer connections using real time communications without needing a server. It supports video, voice, and generic data to be sent between peers, allowing developers to build powerful voice- and video-communication solutions.<\/p>\n<p>You might ask, if WebRTC is establishing p2p connections, what\u2019s differs it from web sockets?<\/p>\n<p>With web sockets, there\u2019s a connection only between the client and server. If a client wants something, it makes request to the server and the server responds to establish the connection. Now imagine that with multiple clients and a server. If one of the clients has an update, it sends it to the server, the server processes the data and sends the update to the other clients. It\u2019s important to note that there\u2019s a some sort of delay in this process.\nThis delay becomes very noticeable when it comes down to applications such as live video streaming, voice chat, and every other application where a second changes a lot of things.<\/p>\n<p>With WebRTC, the client can directly communicate with each other and completely bypass the server. This in turn decreases latency by a lot because the receiving client doesn\u2019t have to wait for the server. You can think of it this way, client 1 asks the server for information from client 2, the server informs client 2 that client 1 needs information from it, a connection is established between client 1 and client 2 and the server becomes obselete.<\/p>\n<h2>Pre-requisites<\/h2>\n<p>I recommend you have the following to flow with this tutorial<\/p>\n<ul>\n<li>Knowledge of JavaScript and React<\/li>\n<li>Nodejs &gt;v14 installed<\/li>\n<li>A code editor (VS Code preferably)<\/li>\n<\/ul>\n<p>The complete code and demo is on <a href=\"https:\/\/codesandbox.io\/embed\/react-video-chat-forked-vp5e3w?autoresize=1&amp;fontsize=14&amp;hidenavigation=1&amp;theme=dark\">Codesandbox<\/a><\/p>\n<\/div>\n  \n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/react-video-chat-forked-vp5e3w?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"react-video-chat-forked-vp5e3w?\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n  <div class=\"wp-block-cloudinary-markdown \"><h2>What we will be building<\/h2>\n<p>Now we\u2019ve gotten a brief overview of WebRTC, we will be building a web application that utilizes the technology. We will use <code>express<\/code> and <code>socket.io<\/code> for our server and on the frontend, we\u2019ll use <code>socket.io-client<\/code> and <code>simple-peer<\/code>. <code>simple-peer<\/code> is a JavaScript wrapper for WebRTC and we\u2019ll be using it to simplify the WebRTC integration in our app.<\/p>\n<p>Let\u2019s get started already.<\/p>\n<h2>Getting Started<\/h2>\n<p>We will start by setting up our server. Run this command to create a folder and node project<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-id\">#bash<\/span>\n<span class=\"hljs-selector-tag\">mkdir<\/span> <span class=\"hljs-selector-tag\">webrtc-react-video-chat<\/span> &amp;&amp; <span class=\"hljs-selector-tag\">cd<\/span> <span class=\"hljs-selector-tag\">webrtc-react-video-chat<\/span>\n<span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">init<\/span> <span class=\"hljs-selector-tag\">--y<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p><code>npm init<\/code> <code>--``y<\/code> will generate a package.json. Open the directory in your code editor and install these dependencies.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">i<\/span> <span class=\"hljs-selector-tag\">cors<\/span> <span class=\"hljs-selector-tag\">express<\/span> <span class=\"hljs-selector-tag\">nodemon<\/span> <span class=\"hljs-selector-tag\">socket<\/span><span class=\"hljs-selector-class\">.io<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p><code>cors<\/code>: this package will enable cors on our server, so we won\u2019t have cross-origin issues when we try connecting the frontend.\n<code>express<\/code>: express is a nodejs web framework.\n<code>nodemon<\/code>: nodemon is a tool that helps develop Node.js based applications by automatically restarting the node application when file changes in the directory are detected. We will use it to watch live changes.\n<code>socket.io<\/code>: this is the server library for Socket IO. Socket.IO enables real-time bidirectional event-based communication.\nGo ahead to create an <code>index.js<\/code> and add these lines of code<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/index.js<\/span>\n<span class=\"hljs-keyword\">const<\/span> app = <span class=\"hljs-keyword\">require<\/span>(<span class=\"hljs-string\">\"express\"<\/span>)();\n<span class=\"hljs-keyword\">const<\/span> server = <span class=\"hljs-keyword\">require<\/span>(<span class=\"hljs-string\">\"http\"<\/span>).createServer(app);\n<span class=\"hljs-keyword\">const<\/span> cors = <span class=\"hljs-keyword\">require<\/span>(<span class=\"hljs-string\">\"cors\"<\/span>);\n    \napp.<span class=\"hljs-keyword\">use<\/span>(<span class=\"hljs-title\">cors<\/span>());\n<span class=\"hljs-keyword\">const<\/span> PORT = process.env.PORT || <span class=\"hljs-number\">8080<\/span>;\n\napp.get(<span class=\"hljs-string\">'\/'<\/span>, (req, res) =&gt; {\n    res.send(<span class=\"hljs-string\">'Hello World'<\/span>);\n});\n\nserver.listen(PORT, () =&gt; console.log(`Server is running on port ${PORT}`));\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>If you\u2019ve worked with JavaScript at some level, you will find this familiar. We\u2019ve just created a simple express server. To run this server, run this command on your terminal.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">node<\/span> <span class=\"hljs-selector-tag\">index<\/span><span class=\"hljs-selector-class\">.js<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You should get something like this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\">\u279c  <span class=\"hljs-selector-tag\">webrtc-react-video-chat<\/span> <span class=\"hljs-selector-tag\">node<\/span> <span class=\"hljs-selector-tag\">index<\/span><span class=\"hljs-selector-class\">.js<\/span>\n<span class=\"hljs-selector-tag\">Server<\/span> <span class=\"hljs-selector-tag\">is<\/span> <span class=\"hljs-selector-tag\">running<\/span> <span class=\"hljs-selector-tag\">on<\/span> <span class=\"hljs-selector-tag\">port<\/span> 8080\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Now, add this line to the <code>scripts<\/code> block in your <code>package.json<\/code><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-string\">\"start\"<\/span>: <span class=\"hljs-string\">\"nodemon index.js\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This ensures we use nodemon to run our server. You can now use <code>npm run start<\/code> to start the server. Awesome!\nLet\u2019s go ahead to integrate Socket.IO to our server. Update your <code>index.js<\/code> to look like this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">#index.js<\/span>\n<span class=\"hljs-keyword\">const<\/span> app = <span class=\"hljs-keyword\">require<\/span>(<span class=\"hljs-string\">\"express\"<\/span>)();\n<span class=\"hljs-keyword\">const<\/span> server = <span class=\"hljs-keyword\">require<\/span>(<span class=\"hljs-string\">\"http\"<\/span>).createServer(app);\n<span class=\"hljs-keyword\">const<\/span> cors = <span class=\"hljs-keyword\">require<\/span>(<span class=\"hljs-string\">\"cors\"<\/span>);\n<span class=\"hljs-keyword\">const<\/span> io = <span class=\"hljs-keyword\">require<\/span>(<span class=\"hljs-string\">\"socket.io\"<\/span>)(server, {\n    cors: {\n        origin: <span class=\"hljs-string\">\"*\"<\/span>,\n        methods: &#91;<span class=\"hljs-string\">\"GET\"<\/span>, <span class=\"hljs-string\">\"POST\"<\/span>]\n    }\n});\n\napp.<span class=\"hljs-keyword\">use<\/span>(<span class=\"hljs-title\">cors<\/span>());\n<span class=\"hljs-keyword\">const<\/span> PORT = process.env.PORT || <span class=\"hljs-number\">8080<\/span>;\napp.get(<span class=\"hljs-string\">'\/'<\/span>, (req, res) =&gt; {\n        res.send(<span class=\"hljs-string\">'Hello World'<\/span>);\n});\n\nio.on(<span class=\"hljs-string\">\"connection\"<\/span>, (socket) =&gt; {\n    socket.emit(<span class=\"hljs-string\">\"me\"<\/span>, socket.id);\n    socket.on(<span class=\"hljs-string\">\"disconnect\"<\/span>, () =&gt; {\n        socket.broadcast.emit(<span class=\"hljs-string\">\"callEnded\"<\/span>)\n    });\n    socket.on(<span class=\"hljs-string\">\"callUser\"<\/span>, ({ userToCall, signalData, from, name }) =&gt; {\n        io.to(userToCall).emit(<span class=\"hljs-string\">\"callUser\"<\/span>, { signal: signalData, from, name });\n    });\n    socket.on(<span class=\"hljs-string\">\"answerCall\"<\/span>, (data) =&gt; {\n        io.to(data.to).emit(<span class=\"hljs-string\">\"callAccepted\"<\/span>, data.signal)\n    });\n});\nserver.listen(PORT, () =&gt; console.log(`Server is running on port ${PORT}`));\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Firstly, we initialize the socket.io Server library. Because of this, we have to use the express HTTP module and then the HTTP.createServer() method for our server instance. Now we have initialized the socket server instance, we can now emit and listen to events between the server and client.\nWe start with emitting a <code>me<\/code> message and passing the <code>socket.id<\/code>. This is going to be our <code>id<\/code> (we will get to see this soon).\nNext, we create a disconnect handler and broadcast a callEnded message.\nNext, we have a <code>callUser<\/code> handler, the callback function will receive the following data from the frontend: <code>userToCall<\/code>, <code>signalData<\/code>, <code>from<\/code>, <code>name<\/code>.\nFinally, the last handler is for answering calls. We emit a message <code>callAccepted<\/code> and pass <code>data.signal<\/code> as a callback.\nAwesome! that\u2019s our entire server for this project.\nLet\u2019s go ahead to build the frontend with WebRTC.<\/p>\n<h2>Implementing Frontend<\/h2>\n<p>We will start by installing a React project in our directory. Run this command to do that, make sure you\u2019re in the project directory.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npx create-react-app .\/frontend\n<\/code><\/span><\/pre>\n<p>This will create a frontend directory with our React app in it. Change directory to <code>frontend<\/code> and install these dependencies.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-id\">#bash<\/span>\n<span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">i<\/span> <span class=\"hljs-keyword\">@chakra-ui<\/span>\/react @emotion\/react @emotion\/styled framer-motion react-icons react-copy-to-clipboard simple-peer socket.io-client\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p><code>chakra-ui\/react<\/code>: Chakra UI is a simple, modular and accessible component library that gives you the building blocks you need to build your React applications.\n<code>react-icons<\/code>: We will be using some icons from the react-icons library.\n<code>react-copy-to-clipboard<\/code>: We will be using this package to copy our socket id to clipboard.\n<code>simple-peer<\/code>: Nodejs wrapper for WebRTC.\n<code>socket.io-client<\/code>: Client side JavaScript wrapper for Socket IO.<\/p>\n<p>Let\u2019s flesh out the structure of our project. Delete everything in the <code>src<\/code> folder except <code>App.js<\/code> and <code>index.js<\/code>.  Update your <code>index.js<\/code> to add Chakra UI so we can use Chakra UI globally.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/src\/index.js<\/span>\n    \n<span class=\"hljs-keyword\">import<\/span> React <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> ReactDOM <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react-dom\/client'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> App <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/App'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { ChakraProvider } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@chakra-ui\/react'<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> root = ReactDOM.createRoot(<span class=\"hljs-built_in\">document<\/span>.getElementById(<span class=\"hljs-string\">'root'<\/span>));\nroot.render(\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">React.StrictMode<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ChakraProvider<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">App<\/span> \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ChakraProvider<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">React.StrictMode<\/span>&gt;<\/span><\/span>\n);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, create a components folder in the src directory and add these 3 files; Notifications.jsx, VideoPlayer.jsx, and Options.jsx. The components should initially look like this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">#src\/components\/VideoPlayer.jsx<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> VideoPlayer = () =&gt; {\n    <span class=\"hljs-keyword\">return<\/span> (\n        &lt;div&gt;VideoPlayer&lt;\/div&gt;\n    )\n}\nexport <span class=\"hljs-keyword\">default<\/span> VideoPlayer\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">#src\/components\/Options.jsx<\/span>\n<span class=\"hljs-keyword\">const<\/span> Options = () =&gt; {\n    <span class=\"hljs-keyword\">return<\/span> (\n        &lt;div&gt;Options&lt;\/div&gt;\n    )\n}\nexport <span class=\"hljs-keyword\">default<\/span> Options\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">#src\/components\/Notifications.jsx<\/span>\n<span class=\"hljs-keyword\">const<\/span> Notifications = () =&gt; {\n    <span class=\"hljs-keyword\">return<\/span> (\n        &lt;div&gt;Notifications&lt;\/div&gt;\n    )\n}\nexport <span class=\"hljs-keyword\">default<\/span> Notifications\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Update your <code>App.js<\/code> to look like this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">#src\/App.js<\/span>\nimport { Box, Heading, Container } from <span class=\"hljs-string\">'@chakra-ui\/react'<\/span>;\nimport Notifications from <span class=\"hljs-string\">'.\/components\/Notifications'<\/span>;\nimport Options from <span class=\"hljs-string\">'.\/components\/Options'<\/span>;\nimport VideoPlayer from <span class=\"hljs-string\">'.\/components\/VideoPlayer'<\/span>;\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">App<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n    <span class=\"hljs-keyword\">return<\/span> (\n        &lt;Box&gt;\n          &lt;Container maxW=<span class=\"hljs-string\">\"1200px\"<\/span> mt=<span class=\"hljs-string\">\"8\"<\/span>&gt;\n            &lt;Heading <span class=\"hljs-keyword\">as<\/span>=<span class=\"hljs-string\">\"h2\"<\/span> size=<span class=\"hljs-string\">\"2xl\"<\/span>&gt; Video Chat App &lt;\/Heading&gt;\n            &lt;VideoPlayer \/&gt;\n            &lt;Options \/&gt;\n            &lt;Notifications \/&gt;\n          &lt;\/Container&gt;\n        &lt;\/Box&gt;\n    );\n}\nexport <span class=\"hljs-keyword\">default<\/span> App;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Navigate to <a href=\"https:\/\/localhost:3000\">https:\/\/localhost:3000<\/a> on your browser and you should see something like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_97CA2598FD50B691F031DC93846452A1506B97F99F8953CFD918B0F21965CB16_1658446345001_Screenshot+2022-07-22+at+00.32.00.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1097\"\/><\/p>\n<p>Awesome. Now let\u2019s write the logic for our application. We will be using React Context API for this. If you haven\u2019t used it before, pause here and read the <a href=\"https:\/\/reactjs.org\/docs\/context.html\">documentation<\/a> on Context API.\nCreate a <code>Context.js<\/code> in your src folder and add these lines of code.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">#src\/Context.js<\/span>\nimport { createContext, useState, useRef, useEffect } from <span class=\"hljs-string\">'react'<\/span>;\nimport { io } from <span class=\"hljs-string\">'socket.io-client'<\/span>;\nimport Peer from <span class=\"hljs-string\">'simple-peer'<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> SocketContext = createContext();\n<span class=\"hljs-keyword\">const<\/span> socket = io(<span class=\"hljs-string\">'http:\/\/localhost:8080'<\/span>);\n<span class=\"hljs-keyword\">const<\/span> ContextProvider = ({ children }) =&gt; {\n    <span class=\"hljs-keyword\">const<\/span> &#91;callAccepted, setCallAccepted] = useState(<span class=\"hljs-keyword\">false<\/span>);\n    <span class=\"hljs-keyword\">const<\/span> &#91;callEnded, setCallEnded] = useState(<span class=\"hljs-keyword\">false<\/span>);\n    <span class=\"hljs-keyword\">const<\/span> &#91;stream, setStream] = useState();\n    <span class=\"hljs-keyword\">const<\/span> &#91;name, setName] = useState(<span class=\"hljs-string\">''<\/span>);\n    <span class=\"hljs-keyword\">const<\/span> &#91;call, setCall] = useState({});\n    <span class=\"hljs-keyword\">const<\/span> &#91;me, setMe] = useState(<span class=\"hljs-string\">''<\/span>);\n    <span class=\"hljs-keyword\">const<\/span> myVideo = useRef();\n    <span class=\"hljs-keyword\">const<\/span> userVideo = useRef();\n    <span class=\"hljs-keyword\">const<\/span> connectionRef = useRef();\n    \n    useEffect(() =&gt; {\n        navigator.mediaDevices.getUserMedia({ video: <span class=\"hljs-keyword\">true<\/span>, audio: <span class=\"hljs-keyword\">true<\/span> })\n        .then((currentStream) =&gt; {\n            setStream(currentStream);\n            myVideo.current.srcObject = currentStream;\n        });\n        \n        socket.on(<span class=\"hljs-string\">'me'<\/span>, (id) =&gt; setMe(id));\n        socket.on(<span class=\"hljs-string\">'callUser'<\/span>, ({ from, name: callerName, signal }) =&gt; {\n            setCall({ isReceivingCall: <span class=\"hljs-keyword\">true<\/span>, from, name: callerName, signal });\n        });\n    }, &#91;]);\n    \n    <span class=\"hljs-keyword\">const<\/span> answerCall = () =&gt; {\n        setCallAccepted(<span class=\"hljs-keyword\">true<\/span>);\n        <span class=\"hljs-keyword\">const<\/span> peer = <span class=\"hljs-keyword\">new<\/span> Peer({ initiator: <span class=\"hljs-keyword\">false<\/span>, trickle: <span class=\"hljs-keyword\">false<\/span>, stream });\n        peer.on(<span class=\"hljs-string\">'signal'<\/span>, (data) =&gt; {\n            socket.emit(<span class=\"hljs-string\">'answerCall'<\/span>, { signal: data, to: call.from });\n        });\n        peer.on(<span class=\"hljs-string\">'stream'<\/span>, (currentStream) =&gt; {\n            userVideo.current.srcObject = currentStream;\n        });\n        peer.signal(call.signal);\n        connectionRef.current = peer;\n    };\n    \n    <span class=\"hljs-keyword\">const<\/span> callUser = (id) =&gt; {\n        <span class=\"hljs-keyword\">const<\/span> peer = <span class=\"hljs-keyword\">new<\/span> Peer({ initiator: <span class=\"hljs-keyword\">true<\/span>, trickle: <span class=\"hljs-keyword\">false<\/span>, stream });\n        peer.on(<span class=\"hljs-string\">'signal'<\/span>, (data) =&gt; {\n                socket.emit(<span class=\"hljs-string\">'callUser'<\/span>, { userToCall: id, signalData: data, from: me, name });\n        });\n        peer.on(<span class=\"hljs-string\">'stream'<\/span>, (currentStream) =&gt; {\n            userVideo.current.srcObject = currentStream;\n        });\n        socket.on(<span class=\"hljs-string\">'callAccepted'<\/span>, (signal) =&gt; {\n            setCallAccepted(<span class=\"hljs-keyword\">true<\/span>);\n            peer.signal(signal);\n        });\n        connectionRef.current = peer;\n    };\n    \n    <span class=\"hljs-keyword\">const<\/span> leaveCall = () =&gt; {\n        setCallEnded(<span class=\"hljs-keyword\">true<\/span>);\n        connectionRef.current.destroy();\n        window.location.reload();\n    };\n    \n    <span class=\"hljs-keyword\">return<\/span> (\n        &lt;SocketContext.Provider value={{\n            call,\n            callAccepted,\n            myVideo,\n            userVideo,\n            stream,\n            name,\n            setName,\n            callEnded,\n            me,\n            callUser,\n            leaveCall,\n            answerCall,\n        }}\n        &gt;\n            {children}\n        &lt;\/SocketContext.Provider&gt;\n    );\n};\nexport { ContextProvider, SocketContext };\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Let\u2019s break down this code snippet into chunks.\nFirst, we create our initial context with <code>const<\/code> <code>*SocketContext*<\/code> <code>=<\/code> <code>*createContext*``();<\/code>.\nNext, we create the initial instance of Socket IO with <code>const<\/code> <code>*socket*<\/code> <code>=<\/code> <code>*io*``('http:\/\/localhost:8080');<\/code>. You can recall that\u2019s our server address.\nNext, we call a useEffect hook that asks for permission to use the camera and microphone. We do that using  <code>*navigator.mediaDevices.getUserMedia*``({<\/code> <code>*video*``:<\/code> <code>*true*``,<\/code> <code>*audio*``:<\/code> <code>*true*<\/code> <code>})<\/code>.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> myVideo = useRef(); \n.then(<span class=\"hljs-function\">(<span class=\"hljs-params\">currentStream<\/span>) =&gt;<\/span> {\n    setStream(currentStream);\n    myVideo.current.srcObject = currentStream;\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here, we set the current stream. Furthermore, since we want to populate the video iframe with the <code>src<\/code> of our stream we introduce a <code>myVideo<\/code> ref.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> &#91;me, setMe] = useState(<span class=\"hljs-string\">''<\/span>);\n<span class=\"hljs-keyword\">const<\/span> &#91;call, setCall] = useState({});\nsocket.on(<span class=\"hljs-string\">'me'<\/span>, (id) =&gt; setMe(id));\n    socket.on(<span class=\"hljs-string\">'callUser'<\/span>, ({ <span class=\"hljs-keyword\">from<\/span>, <span class=\"hljs-attr\">name<\/span>: callerName, signal }) =&gt; {\n        setCall({ <span class=\"hljs-attr\">isReceivingCall<\/span>: <span class=\"hljs-literal\">true<\/span>, <span class=\"hljs-keyword\">from<\/span>, <span class=\"hljs-attr\">name<\/span>: callerName, signal });\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Remember in the server when we emitted the <code>socket.id<\/code> with a <code>me<\/code> action, we listen to it here and set it to <code>setMe<\/code>.\nWe have 3 functions here, let\u2019s deal with each of them.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> answerCall = () =&gt; {\n    setCallAccepted(<span class=\"hljs-keyword\">true<\/span>);\n    <span class=\"hljs-keyword\">const<\/span> peer = <span class=\"hljs-keyword\">new<\/span> Peer({ initiator: <span class=\"hljs-keyword\">false<\/span>, trickle: <span class=\"hljs-keyword\">false<\/span>, stream });\n    peer.on(<span class=\"hljs-string\">'signal'<\/span>, (data) =&gt; {\n        socket.emit(<span class=\"hljs-string\">'answerCall'<\/span>, { signal: data, to: call.from });\n    });\n    peer.on(<span class=\"hljs-string\">'stream'<\/span>, (currentStream) =&gt; {\n        userVideo.current.srcObject = currentStream;\n    });\n    peer.signal(call.signal);\n    connectionRef.current = peer;\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We set a boolean state to check if the call has been accepted. Next, we introduce WebRTC by initializing a Peer using the simple-peer package. Peer has actions and handlers just like Socket IO. Once we receive a signal, we execute the data as callback function. In the function, we emit the answer call event and pass in the signal data, and who we are answering the call from.\nNext, we call the stream handler. Here, we get the current stream and pass the ref for the userVideo(we will be creating this soon). Finally, we create a <code>connectionRef<\/code>. This means our current connection is equal to the current peer.<\/p>\n<p>Let\u2019s take a look at the <code>callUser()<\/code><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> callUser = (id) =&gt; {\n    <span class=\"hljs-keyword\">const<\/span> peer = <span class=\"hljs-keyword\">new<\/span> Peer({ initiator: <span class=\"hljs-keyword\">true<\/span>, trickle: <span class=\"hljs-keyword\">false<\/span>, stream });\n    peer.on(<span class=\"hljs-string\">'signal'<\/span>, (data) =&gt; {\n        socket.emit(<span class=\"hljs-string\">'callUser'<\/span>, { userToCall: id, signalData: data, from: me, name });\n    });\n    peer.on(<span class=\"hljs-string\">'stream'<\/span>, (currentStream) =&gt; {\n        userVideo.current.srcObject = currentStream;\n    });\n    socket.on(<span class=\"hljs-string\">'callAccepted'<\/span>, (signal) =&gt; {\n        setCallAccepted(<span class=\"hljs-keyword\">true<\/span>);\n        peer.signal(signal);\n    });\n    connectionRef.current = peer;\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This is similar to the <code>answerCall()<\/code>.\nNotice that the <code>initiator<\/code> key here is set to true. This is because we are the user initiating the call. The signal handler here is emitting the <code>callUser<\/code> event and we pass in the following <code>{<\/code> <code>*userToCall*``:<\/code> <code>**``id,<\/code> <code>*signalData*``:<\/code> <code>**``data,<\/code> <code>*from*``:<\/code> <code>**``me,<\/code> <code>**``name}<\/code>. Finally, the <code>callAccepted<\/code> action which has <code>signal<\/code> passed as callback function enables the user to accept our call.<\/p>\n<p>Next is the <code>leaveCall()<\/code>. This function contains logic for leaving a call.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> leaveCall = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    setCallEnded(<span class=\"hljs-literal\">true<\/span>);\n    connectionRef.current.destroy();\n    <span class=\"hljs-built_in\">window<\/span>.location.reload();\n};\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We set <code>callEnded<\/code> to be true here, then we destroy the connection and stop receiving input from user camera and audio. That\u2019s it for the functions.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SocketContext.Provider<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{{<\/span>\n        <span class=\"hljs-attr\">call<\/span>,\n        <span class=\"hljs-attr\">callAccepted<\/span>,\n        <span class=\"hljs-attr\">myVideo<\/span>,\n        <span class=\"hljs-attr\">userVideo<\/span>,\n        <span class=\"hljs-attr\">stream<\/span>,\n        <span class=\"hljs-attr\">name<\/span>,\n        <span class=\"hljs-attr\">setName<\/span>,\n        <span class=\"hljs-attr\">callEnded<\/span>,\n        <span class=\"hljs-attr\">me<\/span>,\n        <span class=\"hljs-attr\">callUser<\/span>,\n        <span class=\"hljs-attr\">leaveCall<\/span>,\n        <span class=\"hljs-attr\">answerCall<\/span>,\n    }}\n    &gt;<\/span>\n        {children}\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">SocketContext.Provider<\/span>&gt;<\/span><\/span>\n);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Finally for our SocketContext, we return all the state values, refs and functions.<\/p>\n<p>Update your <code>index.js<\/code> to look like this so we have access to the SocketContext all over the app.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">#src\/index.js<\/span>\nimport React from <span class=\"hljs-string\">'react'<\/span>;\nimport ReactDOM from <span class=\"hljs-string\">'react-dom\/client'<\/span>;\nimport App from <span class=\"hljs-string\">'.\/App'<\/span>;\nimport { ChakraProvider } from <span class=\"hljs-string\">'@chakra-ui\/react'<\/span>\nimport { ContextProvider } from <span class=\"hljs-string\">'.\/Context'<\/span>;\n<span class=\"hljs-keyword\">const<\/span> root = ReactDOM.createRoot(document.getElementById(<span class=\"hljs-string\">'root'<\/span>));\nroot.render(\n    &lt;React.StrictMode&gt;\n        &lt;ContextProvider&gt;\n          &lt;ChakraProvider&gt;\n            &lt;App \/&gt;\n          &lt;\/ChakraProvider&gt;\n        &lt;\/ContextProvider&gt;\n    &lt;\/React.StrictMode&gt;\n);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>If you\u2019ve reached this point, you\u2019re awesome! We\u2019re almost done, let\u2019s go ahead to implement our components.<\/p>\n<h2>Implementing the components<\/h2>\n<p>Let\u2019s start with implementing the <code>VideoPlayer<\/code> component.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">#src\/components\/VideoPlayer\n    \nimport { Grid, Box, Heading } from \"@chakra-ui\/react\"\nimport { SocketContext } from \"..\/Context\"\nimport { useContext } from \"react\"\n\nconst VideoPlayer = () =&gt; {\n    const { name, callAccepted, myVideo, userVideo, callEnded, stream, call } = useContext(SocketContext)\n\nreturn (\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Grid<\/span> <span class=\"hljs-attr\">justifyContent<\/span>=<span class=\"hljs-string\">\"center\"<\/span> <span class=\"hljs-attr\">templateColumns<\/span>=<span class=\"hljs-string\">'repeat(2, 1fr)'<\/span> <span class=\"hljs-attr\">mt<\/span>=<span class=\"hljs-string\">\"12\"<\/span>&gt;<\/span>\n            {\/* my video *\/}\n        {\n            stream &amp;&amp; (\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Grid<\/span> <span class=\"hljs-attr\">colSpan<\/span>=<span class=\"hljs-string\">{1}<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Heading<\/span> <span class=\"hljs-attr\">as<\/span>=<span class=\"hljs-string\">\"h5\"<\/span>&gt;<\/span>\n                            {name || 'Name'}\n                        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Heading<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">video<\/span> <span class=\"hljs-attr\">playsInline<\/span> <span class=\"hljs-attr\">muted<\/span> <span class=\"hljs-attr\">ref<\/span>=<span class=\"hljs-string\">{myVideo}<\/span> <span class=\"hljs-attr\">autoPlay<\/span> <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">\"600\"<\/span> \/&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Grid<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n            )\n        }\n              {\/* user's video *\/}\n        {\n            callAccepted &amp;&amp; !callEnded &amp;&amp; (\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Grid<\/span> <span class=\"hljs-attr\">colSpan<\/span>=<span class=\"hljs-string\">{1}<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Heading<\/span> <span class=\"hljs-attr\">as<\/span>=<span class=\"hljs-string\">\"h5\"<\/span>&gt;<\/span>\n                            {call.name || 'Name'}\n                        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Heading<\/span>&gt;<\/span>\n                        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">video<\/span> <span class=\"hljs-attr\">playsInline<\/span> <span class=\"hljs-attr\">ref<\/span>=<span class=\"hljs-string\">{userVideo}<\/span> <span class=\"hljs-attr\">autoPlay<\/span> <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">\"600\"<\/span> \/&gt;<\/span>\n                    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Grid<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Box<\/span>&gt;<\/span>\n            )\n        }\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Grid<\/span>&gt;<\/span>\n)\n}\n    export default VideoPlayer\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Let\u2019s go through the working parts of this snippet.\nFirstly, we get state, and refs values from our SocketContext. Then, we created two grids. The first grid will be our video, while the other will be the user\u2019s video. We then state that if the stream is active, show my video. Notice the <code>myVideo<\/code> ref in the <code>&lt;video&gt;<\/code> tag there.\nHowever, we want to show the user when they have accepted the call and when the call hasn\u2019t ended. We also display the name of the user, if there\u2019s none we set a placeholder. That\u2019s it!\nNavigate to your browser and allow access to the camera and audio, your page should look like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_97CA2598FD50B691F031DC93846452A1506B97F99F8953CFD918B0F21965CB16_1658452617781_Screenshot+2022-07-22+at+02.16.43.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1093\"\/><\/p>\n<p>It works fine! Awesome.\nLet\u2019s move on to create our Options component. Add these lines of code to <code>Options.jsx<\/code><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">#src\/components\/Options.jsx<\/span>\n\nimport { useState, useContext } from <span class=\"hljs-string\">\"react\"<\/span>\nimport { Button, Input, FormLabel, Heading, Grid, Box, Container, FormControl } from <span class=\"hljs-string\">\"@chakra-ui\/react\"<\/span>\nimport { CopyToClipboard } from <span class=\"hljs-string\">'react-copy-to-clipboard'<\/span>;\nimport { BiClipboard, BiPhoneCall, BiPhoneOff } from <span class=\"hljs-string\">\"react-icons\/bi\"<\/span>;\nimport { SocketContext } from <span class=\"hljs-string\">\"..\/Context\"<\/span>;\n    \n<span class=\"hljs-keyword\">const<\/span> Options = () =&gt; {\n    <span class=\"hljs-keyword\">const<\/span> { me, callAccepted, name, setName, callEnded, leaveCall, callUser } = useContext(SocketContext);\n    <span class=\"hljs-keyword\">const<\/span> &#91;idToCall, setIdToCall] = useState(<span class=\"hljs-string\">''<\/span>);\n\n<span class=\"hljs-keyword\">return<\/span> (\n    &lt;Container maxW=<span class=\"hljs-string\">\"1200px\"<\/span> m=<span class=\"hljs-string\">\"35px 0\"<\/span> p=<span class=\"hljs-string\">\"0\"<\/span>&gt;\n        &lt;Box p=<span class=\"hljs-string\">\"10px\"<\/span> border=<span class=\"hljs-string\">\"2px\"<\/span> borderColor=<span class=\"hljs-string\">\"black\"<\/span> borderStyle=<span class=\"hljs-string\">\"solid\"<\/span>&gt;\n            &lt;FormControl display=<span class=\"hljs-string\">\"flex\"<\/span> flexDirection=<span class=\"hljs-string\">\"column\"<\/span> noValidate aria-autocomplete=<span class=\"hljs-string\">\"none\"<\/span>&gt;\n                &lt;Grid templateColumns=<span class=\"hljs-string\">'repeat(2, 1fr)'<\/span> mt=<span class=\"hljs-string\">\"12\"<\/span>&gt;\n                    &lt;Grid colSpan={<span class=\"hljs-number\">1<\/span>} p=<span class=\"hljs-string\">\"6\"<\/span>&gt;\n                        &lt;Heading <span class=\"hljs-keyword\">as<\/span>=<span class=\"hljs-string\">\"h6\"<\/span>&gt; Account Info &lt;\/Heading&gt;\n                        &lt;FormLabel&gt;Username&lt;\/FormLabel&gt;\n                        &lt;Input type=<span class=\"hljs-string\">'text'<\/span> value={name} onChange={(e) =&gt; setName(e.target.value)} width=<span class=\"hljs-string\">\"100%\"<\/span> \/&gt;\n                        &lt;CopyToClipboard text={me} mt=<span class=\"hljs-string\">\"20\"<\/span>&gt;\n                            &lt;Button leftIcon={&lt;BiClipboard \/&gt;} colorScheme=<span class=\"hljs-string\">'teal'<\/span> variant=<span class=\"hljs-string\">'solid'<\/span>&gt;\n                                Copy ID\n                            &lt;\/Button&gt;\n                        &lt;\/CopyToClipboard&gt;\n                    &lt;\/Grid&gt;\n                    &lt;Grid colSpan={<span class=\"hljs-number\">1<\/span>} p=<span class=\"hljs-string\">\"6\"<\/span>&gt;\n                        &lt;Heading <span class=\"hljs-keyword\">as<\/span>=<span class=\"hljs-string\">\"h6\"<\/span>&gt; Make a Call &lt;\/Heading&gt;\n                        &lt;FormLabel&gt; User id to call &lt;\/FormLabel&gt;\n                        &lt;Input type=<span class=\"hljs-string\">'text'<\/span> value={idToCall} onChange={(e) =&gt; setIdToCall(e.target.value)} width=<span class=\"hljs-string\">\"100%\"<\/span> \/&gt;\n                        {\n                            callAccepted &amp;&amp; !callEnded ? (\n                                &lt;Button leftIcon={&lt;BiPhoneOff \/&gt;} onClick={leaveCall} mt=<span class=\"hljs-string\">\"20\"<\/span> colorScheme=<span class=\"hljs-string\">'teal'<\/span> variant=<span class=\"hljs-string\">'info'<\/span>&gt;\n                                    Hang up\n                                &lt;\/Button&gt;\n                            ) : (\n                                &lt;Button leftIcon={&lt;BiPhoneCall \/&gt;} onClick={() =&gt; callUser(idToCall)} mt=<span class=\"hljs-string\">\"20\"<\/span> colorScheme=<span class=\"hljs-string\">'teal'<\/span> variant=<span class=\"hljs-string\">'solid'<\/span>&gt;\n                                    Call\n                                &lt;\/Button&gt;\n                            )\n                        }\n                    &lt;\/Grid&gt;\n                &lt;\/Grid&gt;\n            &lt;\/FormControl&gt;\n        &lt;\/Box&gt;\n    &lt;\/Container&gt;\n)\n}\nexport <span class=\"hljs-keyword\">default<\/span> Options\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Let\u2019s go through the moving parts in this code snippet.\nHere, we get functions, handlers, and state from our SocketContext. We have two Grids, the first allows the user to type their username and copy the socket id. In the other grid, we have an input that accepts an <code>idToCall<\/code>. Finally, we state that if the call is accepted and ongoing, show the <strong>Hang Up<\/strong> button else, show the <strong>Call<\/strong> button.<\/p>\n<p>Save and Navigate to your browser and you will see something like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_97CA2598FD50B691F031DC93846452A1506B97F99F8953CFD918B0F21965CB16_1658455077014_screencapture-localhost-3000-2022-07-22-02_57_29.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1318\"\/><\/p>\n<p>Awesome! Right now, when we click on the call button nothing happens, let\u2019s fix that with the Notifications component.\nAdd these lines of code to <code>Navigation.jsx<\/code><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">#src\/components\/Navigation.jsx<\/span>\nimport { useContext } from <span class=\"hljs-string\">\"react\"<\/span>\nimport { Box, Button, Heading } from <span class=\"hljs-string\">\"@chakra-ui\/react\"<\/span>\nimport { SocketContext } from <span class=\"hljs-string\">\"..\/Context\"<\/span>\n    \n<span class=\"hljs-keyword\">const<\/span> Notifications = () =&gt; {\n    <span class=\"hljs-keyword\">const<\/span> { answerCall, call, callAccepted } = useContext(SocketContext);\n    \n<span class=\"hljs-keyword\">return<\/span> (\n    &lt;&gt;\n        {call.isReceivingCall &amp;&amp; !callAccepted &amp;&amp; (\n            &lt;Box display=<span class=\"hljs-string\">\"flex\"<\/span> justifyContent=<span class=\"hljs-string\">\"space-around\"<\/span> mb=<span class=\"hljs-string\">\"20\"<\/span>&gt;\n                &lt;Heading <span class=\"hljs-keyword\">as<\/span>=<span class=\"hljs-string\">\"h3\"<\/span>&gt; {call.name} is calling &lt;\/Heading&gt;\n                &lt;Button variant=<span class=\"hljs-string\">\"outline\"<\/span> onClick={answerCall} border=<span class=\"hljs-string\">\"1px\"<\/span> borderStyle=<span class=\"hljs-string\">\"solid\"<\/span> borderColor=<span class=\"hljs-string\">\"black\"<\/span>&gt;\n                    Answer Call\n                &lt;\/Button&gt;\n            &lt;\/Box&gt;\n        )}\n    &lt;\/&gt;\n)\n}\nexport <span class=\"hljs-keyword\">default<\/span> Notifications\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Nothing much is going here. We just get a notification to answer the call.\nNavigate to your browser, you should have something like this<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_97CA2598FD50B691F031DC93846452A1506B97F99F8953CFD918B0F21965CB16_1658455925373_screencapture-localhost-3000-2022-07-22-03_11_13.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1443\"\/>\n<img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_97CA2598FD50B691F031DC93846452A1506B97F99F8953CFD918B0F21965CB16_1658455925662_screencapture-localhost-3000-2022-07-22-03_11_20.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1272\"\/><\/p>\n<p>Awesome!<\/p>\n<h2>Conclusion<\/h2>\n<p>We\u2019ve come to the end of this tutorial. We discussed about WebRTC and how it works, we then went on to build a React video chat app with Socket and Peer (a JS wrapper for WebRTC). I hope you learned one or two things from this.<\/p>\n<h2>Further Reading<\/h2>\n<ul>\n<li>\n<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/WebRTC_API\">WebRTC API<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/webrtc.org\/\">Real-time communication for the web<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/web.dev\/webrtc-basics\/\">Get started with WebRTC<\/a>\n<\/li>\n<\/ul>\n<p>Happy Coding!<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28027,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,177,246,371,394],"class_list":["post-28026","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-javascript","tag-react","tag-under-review","tag-webrtc"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Stream Videos with WebRTC API and React<\/title>\n<meta name=\"description\" content=\"WebRTC (stands for Web Real Time Connection) is a technology that that allows you to create peer to peer connections using real time communications without needing a server. It supports video, voice, and generic data to be sent between peers, allowing developers to build powerful voice- and video-communication solutions.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Stream Videos with WebRTC API and React\" \/>\n<meta property=\"og:description\" content=\"WebRTC (stands for Web Real Time Connection) is a technology that that allows you to create peer to peer connections using real time communications without needing a server. It supports video, voice, and generic data to be sent between peers, allowing developers to build powerful voice- and video-communication solutions.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-08-09T08:10:14+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-02-08T19:27:19+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1681925646\/Web_Assets\/blog\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61-png?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"1280\" \/>\n\t<meta property=\"og:image:height\" content=\"814\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Stream Videos with WebRTC API and React\",\"datePublished\":\"2022-08-09T08:10:14+00:00\",\"dateModified\":\"2025-02-08T19:27:19+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/\"},\"wordCount\":7,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925646\/Web_Assets\/blog\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61.png?_i=AA\",\"keywords\":[\"Guest Post\",\"Javascript\",\"React\",\"Under Review\",\"WebRTC\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/\",\"name\":\"Stream Videos with WebRTC API and React\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925646\/Web_Assets\/blog\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61.png?_i=AA\",\"datePublished\":\"2022-08-09T08:10:14+00:00\",\"dateModified\":\"2025-02-08T19:27:19+00:00\",\"description\":\"WebRTC (stands for Web Real Time Connection) is a technology that that allows you to create peer to peer connections using real time communications without needing a server. It supports video, voice, and generic data to be sent between peers, allowing developers to build powerful voice- and video-communication solutions.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925646\/Web_Assets\/blog\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925646\/Web_Assets\/blog\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61.png?_i=AA\",\"width\":1280,\"height\":814},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Stream Videos with WebRTC API and React\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Stream Videos with WebRTC API and React","description":"WebRTC (stands for Web Real Time Connection) is a technology that that allows you to create peer to peer connections using real time communications without needing a server. It supports video, voice, and generic data to be sent between peers, allowing developers to build powerful voice- and video-communication solutions.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/","og_locale":"en_US","og_type":"article","og_title":"Stream Videos with WebRTC API and React","og_description":"WebRTC (stands for Web Real Time Connection) is a technology that that allows you to create peer to peer connections using real time communications without needing a server. It supports video, voice, and generic data to be sent between peers, allowing developers to build powerful voice- and video-communication solutions.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-08-09T08:10:14+00:00","article_modified_time":"2025-02-08T19:27:19+00:00","og_image":[{"width":1280,"height":814,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1681925646\/Web_Assets\/blog\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61-png?_i=AA","type":"image\/png"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/"},"author":{"name":"","@id":""},"headline":"Stream Videos with WebRTC API and React","datePublished":"2022-08-09T08:10:14+00:00","dateModified":"2025-02-08T19:27:19+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/"},"wordCount":7,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925646\/Web_Assets\/blog\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61.png?_i=AA","keywords":["Guest Post","Javascript","React","Under Review","WebRTC"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/","name":"Stream Videos with WebRTC API and React","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925646\/Web_Assets\/blog\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61.png?_i=AA","datePublished":"2022-08-09T08:10:14+00:00","dateModified":"2025-02-08T19:27:19+00:00","description":"WebRTC (stands for Web Real Time Connection) is a technology that that allows you to create peer to peer connections using real time communications without needing a server. It supports video, voice, and generic data to be sent between peers, allowing developers to build powerful voice- and video-communication solutions.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925646\/Web_Assets\/blog\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925646\/Web_Assets\/blog\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61.png?_i=AA","width":1280,"height":814},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/stream-videos-with-webrtc-api-and-react\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Stream Videos with WebRTC API and React"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925646\/Web_Assets\/blog\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61\/4c033022496a103ed73a913cb7f2731d1635a435-1280x814-1_28027b0a61.png?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28026","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=28026"}],"version-history":[{"count":1,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28026\/revisions"}],"predecessor-version":[{"id":36716,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28026\/revisions\/36716"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28027"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28026"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28026"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28026"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}