<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ekaansh Arora</title>
    <description>The latest articles on DEV Community by Ekaansh Arora (@ekaansharora).</description>
    <link>https://dev.to/ekaansharora</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F242848%2Ff37dcf66-faad-458d-a7d1-da7971451fad.png</url>
      <title>DEV Community: Ekaansh Arora</title>
      <link>https://dev.to/ekaansharora</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ekaansharora"/>
    <language>en</language>
    <item>
      <title>Adding Video Chat or Live Streaming to Your Website in 5 lines of Code Using the Agora Web UIKit</title>
      <dc:creator>Ekaansh Arora</dc:creator>
      <pubDate>Mon, 31 Jan 2022 15:20:02 +0000</pubDate>
      <link>https://dev.to/ekaansharora/adding-video-chat-or-live-streaming-to-your-website-in-5-lines-of-code-using-the-agora-web-uikit-2bne</link>
      <guid>https://dev.to/ekaansharora/adding-video-chat-or-live-streaming-to-your-website-in-5-lines-of-code-using-the-agora-web-uikit-2bne</guid>
      <description>&lt;p&gt;When you’re building a live video streaming or a video conferencing website with Agora, a few technical steps might slow you down. Now with the Agora Web UIKit, you can easily add video calling to your website with just five lines of code! It’s fully featured to boot, and it comes with easy customization and is meant to be extended.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oQt1AaA7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4556/1%2AQZVzK_pHsQd0dV2S-E03Dw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oQt1AaA7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4556/1%2AQZVzK_pHsQd0dV2S-E03Dw.png" alt="" width="880" height="681"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Support for video conferencing and live streaming&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Plug and play, no watermark or branding out of the box&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Responsive layouts for desktop and mobile&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Customizable UI and functionality using React properties&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automatically manage tokens (using two-click server deploy)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dual-stream mode and active speaker detection&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Built using modular functional components that can be recomposed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;TypeScript support, with no third-party dependencies&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Support for use as a web component&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;10,000 free minutes every month&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Agora Web UIKit is built on React. If your website uses plain JavaScript or a different framework like Svelte, Vue, or Angular, you can use the &lt;a href="https://github.com/AgoraIO-Community/Web-React-UIKit/tree/main/web-component"&gt;UIKit as a web component&lt;/a&gt;! You can skip to the last section to learn more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;An Agora developer account (It’s free–&lt;a href="https://sso.agora.io/en/signup?utm_source=medium&amp;amp;utm_medium=blog&amp;amp;utm_campaign=web-uikit-release-blog"&gt;sign up here&lt;/a&gt;!)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Node.js LTS release&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A website built using React&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A modern web browser&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;You can get the code for the &lt;a href="https://github.com/AgoraIO-Community/Web-React-UIKit/tree/main/example"&gt;example on GitHub&lt;/a&gt;. To create a React project with Typescript, you can open a terminal and execute:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app demo --template typescript
cd demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Or you can use your own project. Install the Agora Web UIKit from &lt;a href="https://www.npmjs.com/package/agora-react-uikit"&gt;NPM&lt;/a&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i agora-react-uikit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: At the time of writing this post, the current *agora-react-uikit&lt;/em&gt; release is v0.0.5, and the current &lt;em&gt;agora-rtc-sdk-ng&lt;/em&gt; release is v4.8.1.*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s the set up. You can now run npm start to start the React server and visit the hello world app on localhost:3000.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Video Streaming
&lt;/h2&gt;

&lt;p&gt;This UIKit is easy to set up and contains a high-level component called AgoraUIKit. The component handles the logic and UI for our real-time video experience. We can pass in props to the component to customize the behavior and functionality. Let’s clear the App.tsx file and start writing the code to build a video chatting app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AgoraUIKit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PropsInterface&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;agora-react-uikit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FunctionComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;videocall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setVideocall&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PropsInterface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rtcProps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;Your Agora App ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// pass in channel token if the app is in secure mode&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;callbacks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;EndCall&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setVideocall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’re importing the AgoraUIKit component from the agora-react-uikit package. Inside the App component we have a state variable videoCall. We’ll render the UIKit component when it’s set to true and unmount it when it’s false. We define the Agora App ID and channel name in the rtcProps object along with our role. Users on the same channel can communicate with each other. You can use any alphanumeric string for the channel name.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; If your app is in secure mode, you can generate a token from the Agora console and pass it in for testing. We’ll talk more about how to use tokens in a bit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The callbacks object contains RTC events as keys and callback functions as their value — we use the EndCall event to update the state and unmount the AgoraUIKit component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;videocall&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AgoraUIKit&lt;/span&gt;
          &lt;span class="na"&gt;rtcProps&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rtcProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;callbacks&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callbacks&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kc"&gt;null&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100vw&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100vh&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the return statement, we render the AgoraUIKit component with the rtcProps and callbacks object. (Unmounting the AgoraUIKit component performs the required cleanup automatically.)&lt;/p&gt;

&lt;p&gt;The UIKit component also accepts a third prop, called styleProps, which can be used to customize the look of the application by writing React styling. You can override the default styles for each piece of the UIKit (such as buttons, videos, and containers) with your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  What About Live Streaming?
&lt;/h2&gt;

&lt;p&gt;We have a video conferencing website ready to ship. But let’s now take a look at how to convert this to a live streaming app where the users can join either as a host or an audience member. Hosts can share their audio and video to everyone in the channel, while audience members can only receive video and audio from other hosts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AgoraUIKit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PropsInterface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;agora-react-uikit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FunctionComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;videocall&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setVideocall&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isHost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setHost&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isPinned&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setPinned&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s add two new state variables: isHost and isPinned. The isHost variable will track whether the user is a host or audience, and the isPinned variable is used to switch between the two prebuilt layouts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PropsInterface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rtcProps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;Your Agora App ID&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isHost&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;host&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;audience&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isPinned&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pin&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;callbacks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;EndCall&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setVideocall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;styleProps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;localBtnContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blueviolet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use our state to define our rtcProps. We added the role prop to the rtcProps switch between host and audience (by default the role is host). The UIKit props are dynamic. If you update the state that’s passed as a prop, the UIKit will react to it (like the standard React design pattern). We’re changing the background color of the bottom bar using styleProps so that we can see how that works as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;videocall&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&amp;lt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nav&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;You're &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isHost&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a host&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;an audience&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;btn&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isHost&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Change Role&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;btn&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setPinned&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isPinned&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Change Layout&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AgoraUIKit&lt;/span&gt;
            &lt;span class="na"&gt;rtcProps&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rtcProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;callbacks&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callbacks&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;styleProps&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;styleProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&amp;lt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;btn&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setVideocall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Start Call&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  )
}
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ll update our UI to add buttons that toggle our state. We’ll also add the styleProps to the UIKit. Instead of returning null when our video call state is false, let’s add an &lt;/p&gt;
&lt;h3&gt; tag to start the call once the call has ended by updating our state.

&lt;/h3&gt;
&lt;p&gt;Here’s the updated styling if you want to follow along:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100vw&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100vh&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#007bff22&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;textAlign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;marginBottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;videoContainer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;flexDirection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;column&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CSSProperties&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;nav&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;justifyContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;space-around&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;btn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#007bff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pointer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#ffffff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Customizing Functionality with RtcProps&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The RtcProps object lets you customize how the UIKit works. You can select features and layouts. And there’s a growing list of things to customize using RtcProps. The object type definition can be found &lt;a href="https://agoraio-community.github.io/Web-React-UIKit/interfaces/RtcPropsInterface.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Token Management
&lt;/h2&gt;

&lt;p&gt;If you’re using the Agora Web UIKit in production, we strongly recommend using tokens to secure your app. There are two ways to use them: You can supply a token manually to the UIKit with the &lt;a href="https://agoraio-community.github.io/Web-React-UIKit/interfaces/RtcPropsInterface.html#token"&gt;token&lt;/a&gt; property if you already have a token server set up.&lt;/p&gt;

&lt;p&gt;If you don’t have a token server, you can use the &lt;a href="https://agoraio-community.github.io/Web-React-UIKit/interfaces/RtcPropsInterface.html#tokenUrl"&gt;tokenUrl&lt;/a&gt; property. This can be used to automatically fetch a new access token for the channel and renew it if it is going to expire soon. The functionality for requesting a new token expects the token to follow the URL scheme in the prebuilt Golang token server found on GitHub: &lt;a href="https://github.com/AgoraIO-Community/agora-token-service"&gt;AgoraIO-Community/agora-token-service&lt;/a&gt;. You can deploy it in two clicks to Heroku using &lt;a href="https://www.heroku.com/deploy/?template=https://github.com/AgoraIO-Community/agora-token-service"&gt;this link&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the Web UIKit Without React
&lt;/h3&gt;

&lt;p&gt;The Agora Web UIKit is also available as a web component to be used with websites built with vanilla JavaScript or a framework like Angular, Vue, or Avelte. To add video calling to your website, just import the web component as a script. You can then use the web component in your DOM by passing in your Agora App ID and channel name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"agora-uikit.js"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;agora&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;react&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="na"&gt;uikit&lt;/span&gt;
      &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"width: 100%; height: 100vh; display: flex;"&lt;/span&gt;
      &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;
      &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'test'&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      // select web component
      const el = document.querySelector('agora-react-web-uikit');

      // alternatively you can do this to pass props
      // el.appId = '&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Your&lt;/span&gt; &lt;span class="na"&gt;App&lt;/span&gt; &lt;span class="na"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;'

      // Add event listener and subscribe to custom event
      el.addEventListener('agoraUIKitEndcall', (e) =&amp;gt; &lt;span class="si"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello from html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// handle endcall event&lt;/span&gt;
        &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="si"&gt;}&lt;/span&gt;);
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can access the web component element in JS and update object properties. This lets you programmatically update props, which can be useful in building your buttons to update the user role in a live stream, for example. You can add event listeners for the end call button to handle what happens when the user clicks that button. We’re looking forward to your feedback, you can open a feature request for us to add more RTC events to the web component release.&lt;/p&gt;

&lt;p&gt;There are a few limitations with web components for now. Everything we’ve talked about so far is supported, but the next section is React-specific. We’ll keep adding features and supporting this version of the UIKit alongside the react release, based on your feedback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced: Recomposing the UIKit
&lt;/h2&gt;

&lt;p&gt;If you need finer control or want to build a custom layout for your application that the AgoraUIKit component doesn’t support yet, you can extract and use individual components that make up the UIKit and recompose them together to build your own custom solution without worrying about managing the SDK.&lt;/p&gt;

&lt;p&gt;The UIKit isn’t limited to using the AgoraUIKit component. It’s a high-level component made up of several other modular components, which makes it easy to get started. You can import and use the individual pieces to compose your app.&lt;/p&gt;

&lt;h3&gt;
  
  
  RtcConfigure
&lt;/h3&gt;

&lt;p&gt;The RtcConfigure component contains all the logic for the video call. It handles all the SDK events and maintains the state for the application. You can wrap the other UIKit components inside the RtcConfigure component to get access to user objects.&lt;/p&gt;

&lt;p&gt;It also sets the RtcContext, which can be used to access the Web SDK client object and mediaStore which contains the remote tracks and the local tracks (as well as the dispatch function to mutate the state).&lt;/p&gt;

&lt;h3&gt;
  
  
  TracksConfigure
&lt;/h3&gt;

&lt;p&gt;The TrackConfigure component handles creating audio and video tracks for the app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Controls
&lt;/h3&gt;

&lt;p&gt;The UIKit exports a LocalControls component that wraps LocalAudioMute, LocalVideoMute, and EndCall button components. The library has a RemoteAudioMute, a RemoteVideoMute, and a SwapUser (swaps the user with the maxUser) buttons. These components accept the user object as a prop.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MzI_8TMP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2004/1%2A-dAoGX4Fcec_oVV8H4NdPw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MzI_8TMP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2004/1%2A-dAoGX4Fcec_oVV8H4NdPw.png" alt="" width="880" height="836"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; The remote controls mute the remote user’s audio and video only locally. The change isn’t reflected for anyone else on the call.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Video Views
&lt;/h3&gt;

&lt;p&gt;To render the video of a user, we have two components: MaxVideoView and MinVideoView. Both require a user object as a prop. The user data is divided into two different arrays: MaxUser and MinUser. The MaxUser array always contains only one user; the other users are contained in the MinUser array. In the case of a pinned layout, we can use one array to render the big view and the other to render the video list. You don’t have to interact with the state directly. For example, if you want to swap a user, you can use the SwapUser button, which will internally mutate the state.&lt;/p&gt;

&lt;p&gt;We also have the gridLayout and pinnedLayout components available if you don’t want to build your own layout using the views.&lt;/p&gt;

&lt;h3&gt;
  
  
  Props Context
&lt;/h3&gt;

&lt;p&gt;PropsContext uses the React &lt;a href="https://reactjs.org/docs/context.html"&gt;Context API&lt;/a&gt;, which gives you access to the provider and consumer components. Together, these let you access the props that we pass to this component elsewhere in the component tree. The library uses this to pass rtcProps, styleProps, and callbacks around the component tree.&lt;/p&gt;

&lt;h3&gt;
  
  
  User Contexts
&lt;/h3&gt;

&lt;p&gt;The MaxUidContext gives you access to an array containing an object for the user in the MaxView (main view in the floating layout). The MinUidContext gives you access to an array of objects for the users in the MinView (top floating view in the floating layout). The LocalUserContext gives you access to the local user’s state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example of Recomposing
&lt;/h2&gt;

&lt;p&gt;Let’s see all these components in action by building our own high-level component. The following example omits trivial details for clarity and ease of explanation (like defining props and styles). You can look at the AgoraUIKit component if you need more information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;RtcConfigure&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./RTCConfigure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PropsContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PropsProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PropsInterface&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./PropsContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;LocalControls&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Controls/LocalControls&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;TracksConfigure&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./TracksConfigure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MaxUidContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MaxVideoView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MinUidContext&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;RtcContext&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./RtcContext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AgoraUIKit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PropsInterface&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rtcProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// define your props&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;PropsProvider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rtcProps&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rtcProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;audience&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;VideocallUI&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TracksConfigure&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;VideocallUI&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;TracksConfigure&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;PropsProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;VideocallUI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rtcProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PropsContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RtcConfigure&lt;/span&gt; &lt;span class="na"&gt;callActive&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rtcProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callActive&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RenderVideos&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LocalControls&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;RtcConfigure&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;RenderVideos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MaxUidContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MinUidContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;min&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="c1"&gt;// you can access the Web SDK client and tracks here&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;localVideoTrack&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RtcContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getRTCStats&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localVideoTrack&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;getCurrentFrameData&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MaxVideoView&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;AgoraUIKit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We wrap our application in  to give the other components access to the props. If the user is a host, we wrap the  in the  component that creates and passes along the microphone and camera tracks.&lt;/p&gt;

&lt;p&gt;The  is wrapped by , which contains all the logic for our video call or live stream and also sets up the local or remote user state. We render the control bottom bar using  next to the  component that accesses the user contexts and renders the videos using the  component mapping over each user.&lt;/p&gt;

&lt;p&gt;You can find an example &lt;a href="https://github.com/EkaanshArora/Agora-Web-UIKit-RTMP"&gt;here&lt;/a&gt; that shows how to add RTMP streaming to the Web UIKit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We’re looking forward to your contributions. If you have a feature request, please open a pull request. If you find a bug, please report it on GitHub issues. We also have similar UIKits for &lt;a href="https://github.com/AgoraIO-Community/Android-UIKit"&gt;Android&lt;/a&gt;, &lt;a href="https://github.com/AgoraIO-Community/iOS-UIKit"&gt;iOS&lt;/a&gt;, &lt;a href="https://github.com/AgoraIO-Community/ReactNative-UIKit"&gt;React Native&lt;/a&gt;, and &lt;a href="https://github.com/AgoraIO-Community/Flutter-UIKit"&gt;Flutter&lt;/a&gt;, so be sure to check those out as well.&lt;/p&gt;

&lt;p&gt;If you have questions while using the Web UIKit, I invite you to join the &lt;a href="https://agora.io/en/join-slack"&gt;Agora Developer Slack community&lt;/a&gt;, where you can ask them in the #web-help-me channel. Feel free to open issues for feature requests or to report bugs on the&lt;a href="https://github.com/AgoraIO-Community/Web-React-UIKit/issues"&gt; GitHub Repo&lt;/a&gt;. Or you can reach out to me on &lt;a href="https://twitter.com/ekaansh"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>react</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Dynamic Channels for Video Chat Using Agora RTM on React Native</title>
      <dc:creator>Ekaansh Arora</dc:creator>
      <pubDate>Fri, 10 Dec 2021 16:25:39 +0000</pubDate>
      <link>https://dev.to/ekaansharora/dynamic-channels-for-video-chat-using-agora-rtm-on-react-native-851</link>
      <guid>https://dev.to/ekaansharora/dynamic-channels-for-video-chat-using-agora-rtm-on-react-native-851</guid>
      <description>&lt;p&gt;The Agora RTC (Real-time Communication) SDK makes it easy to build video chat apps on React Native. We can have multiple users communicate with each other by using the same channel name for our video chat room.&lt;/p&gt;

&lt;p&gt;If you’re building a social video chat app, you might want to let your users generate rooms that other users can browse, join, and communicate in. You can do this with a back-end server to handle these requests and update other users with information about created rooms, but that would involve writing back-end code and hosting your own server.&lt;/p&gt;

&lt;p&gt;In this tutorial, we’re going to see an alternative way of achieving the same goal by using the Agora RTM (Real-time Messaging) SDK. We’ll use messages sent by users to communicate the creation and updating of dynamic video chat rooms, all with front-end code.&lt;/p&gt;

&lt;p&gt;This can be handy because when you don’t want to build a back-end server, you can use messages to update other users on the status of the rooms. This approach can be easily extended to having fully managed rooms as well as features like admin admit/deny a user, mute another user, and remove a user from the room.&lt;/p&gt;

&lt;p&gt;We’ll be using the &lt;a href="https://www.npmjs.com/package/react-native-agora/"&gt;Agora RTC SDK&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/agora-react-native-rtm"&gt;Agora RTM SDK&lt;/a&gt; for React Native in this example. I’m using v3.2.2 of the RTC SDK and v1.2.2-alpha.3 of the RTM SDK at the time of writing.&lt;/p&gt;

&lt;h1&gt;
  
  
  Project Overview
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;  We have an RTM room called ‘lobby’. We’ll use it to signal users when someone creates a new room or when the members in a room change.&lt;/li&gt;
&lt;li&gt;  The way we’ll do this is by having the most senior member in the video chat room send messages to others. The oldest member in the room is considered the senior member, more on this later.&lt;/li&gt;
&lt;li&gt;  We’ll send messages in the form of ‘roomName:memberCount’ which can be processed by other users to store the room name and member count as a dictionary in their application state. We’ll use it to render a list of rooms with the number of members in it.&lt;/li&gt;
&lt;li&gt;  Once we have the list, we can join the room by using the RTC SDK. We’ll also need to listen for users joining and leaving to update the member count for everyone else. This is done only by the senior member to avoid overhead.&lt;/li&gt;
&lt;li&gt;  We also need to consider two cases to update room information for other users. First, when a new user joins the lobby, the senior-most member in each channel sends the user a peer message. Second, when a channel’s member count is updated we send a channel message to all users connected to the lobby to update their room list.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Creating an Agora account
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://sso.agora.io/en/signup?utm_source=medium&amp;amp;utm_medium=blog&amp;amp;utm_campaign=dynamic-channels-for-video-chat-using-agora-rtm-on-react-native"&gt;Sign up&lt;/a&gt; for an account and log in to the dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fpcRRT4g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1000/1%255C%2AYFtAcuBfRmPXr8DGEA79SA.png" class="article-body-image-wrapper"&gt;&lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--fpcRRT4g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1000/1%255C%2AYFtAcuBfRmPXr8DGEA79SA.png" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigate to the Project List tab under the Project Management tab, and create a project by clicking the blue Create button. (When prompted to use App ID + Certificate, select only App ID.) The App ID will be used to authorize your requests while you’re developing the application, without generating tokens. Copy the App ID someplace safe, we’ll need it in a bit.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; This guide does not implement token authentication, which is recommended for all RTE apps running in production environments. For more information about token-based authentication in the Agora platform, see &lt;a href="https://docs.agora.io/en/Video/token?platform=All%20Platforms"&gt;https://docs.agora.io/en/Video/token?platform=All%20Platforms&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Download the Source
&lt;/h1&gt;

&lt;p&gt;You can jump to the code if you like. The code is open source and available on &lt;a href="https://github.com/EkaanshArora/Agora-Dynamic-VideoChat-Rooms"&gt;GitHub&lt;/a&gt;. To try it out for yourself, see the readme for steps on how to run the app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hhK6Y-V3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1i59dx7t50uygmyxcvnm.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hhK6Y-V3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1i59dx7t50uygmyxcvnm.jpeg" alt="Screenshots from the app running on an Android Emulator" width="880" height="882"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Structure of our example
&lt;/h1&gt;

&lt;p&gt;This is the structure of the application that we are building:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**.**  
├── android  
├── components  
│ └── **Permission.ts**  
│ └── **Style.ts**  
├── ios  
├── **App.tsx  
.**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  App.tsx
&lt;/h2&gt;

&lt;p&gt;App.tsx will be the entry point into the app. We’ll have all our code in this file.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;We start by writing the import statements. Next, we define an interface for our application state containing the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;**appId**&lt;/code&gt;: our Agora App ID&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;**token**&lt;/code&gt;: token generated to join the channel&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;**inCall**&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt; boolean to store if we’re in an active video chat room&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;**inLobby**&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt; boolean to store if we’re in the lobby&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;**input**&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt; string to store input when creating a new room&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;**peerIdsRTC**&lt;/code&gt;: array to store the RTC UIDs of other users in the video chat room&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;**seniors**&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt; array storing RTM members who have joined the video chat room before us&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;**myUsername**&lt;/code&gt;: local user’s name to log in to RTM&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;**rooms**&lt;/code&gt;&lt;strong&gt;:&lt;/strong&gt; dictionary to store room names and their member count&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We define a class-based component: the &lt;code&gt;_rtcEngine&lt;/code&gt; variable will store the instance of the RtcEngine class, and the &lt;code&gt;_rtmEngine&lt;/code&gt; variable will store the instance of the RtmEngine class, which we can use to access the SDK functions.&lt;/p&gt;

&lt;p&gt;In the constructor, we set our state variables and request permission for recording audio on Android. (We use a helper function from &lt;code&gt;permission.ts&lt;/code&gt; as described below.) When the component is mounted, we call the &lt;code&gt;initRTC&lt;/code&gt;  and &lt;code&gt;initRTM&lt;/code&gt; functions, which initialize the RTC and RTM engines using the App ID. When the component unmounts, we destroy our engine instances.&lt;/p&gt;

&lt;h2&gt;
  
  
  RTC Initialization
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We use the App ID to create our engine instance. We use the &lt;code&gt;enableVideo&lt;/code&gt; method to set the SDK in video mode.&lt;/p&gt;

&lt;p&gt;The RTC triggers a &lt;code&gt;userJoined&lt;/code&gt; event for each user present when we join the channel and for each new user who joins later. The &lt;code&gt;userOffline&lt;/code&gt; event is triggered when a user leaves the channel. We use event listeners to keep our peerIds array updated with UIDs. We will use this array later to render the video feeds from other users.&lt;/p&gt;

&lt;p&gt;Once we’ve joined a channel, the SDK triggers the &lt;code&gt;JoinChannelSuccess&lt;/code&gt; event. We set our state variable &lt;code&gt;inCall&lt;/code&gt; as true to render the video chat UI.&lt;/p&gt;

&lt;p&gt;When a new user joins our video chat room, if we’re the senior member as discussed before, we send a channel message with the updated user count to all members across channels using the &lt;code&gt;lobby&lt;/code&gt; RTM channel.&lt;/p&gt;

&lt;h2&gt;
  
  
  RTM Initialization
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We’re using RTM to send our room name and member count. We maintain an array of seniors, that is, members who have joined the call before us. If the seniors array size is &amp;lt;2, it means we’re the senior-most member, responsible for the signaling. (The local user is also part of the array.)&lt;/p&gt;

&lt;p&gt;First, we attach the &lt;code&gt;channelMemberJoined&lt;/code&gt; and &lt;code&gt;channelMemberLeft&lt;/code&gt; listeners, which are triggered when a user joins or leaves the RTM channel. When a user joins the lobby channel, if we’re the senior-most member we send them a peer message. If a user leaves the current video chat channel, we update the seniors array (removing them from it if they had arrived before us). We also send a channel message to the lobby if we are the senior member updating the count.&lt;/p&gt;

&lt;p&gt;Next, we attach the &lt;code&gt;channelMessageReceived&lt;/code&gt; and &lt;code&gt;messageReceived&lt;/code&gt; event listeners, which are triggered when we receive a channel message and a peer message, respectively. We split the &lt;code&gt;channelName:memberCount&lt;/code&gt; string (for example, &lt;code&gt;‘helloWorld:5’&lt;/code&gt;) and use the two pieces of data to update our dictionary. (for example, &lt;code&gt;rooms: { ‘helloWorld’: 5, ‘roomTwo’: 3 }&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Join a Call
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We define a function to join the call that takes in the channel name as an argument. We update the state with the channel name and join the channel on both RTM and RTC, using the &lt;code&gt;joinChannel&lt;/code&gt; methods.&lt;/p&gt;

&lt;p&gt;We use the &lt;code&gt;getChannelMembersBychannelId&lt;/code&gt; method on RTM to get the UIDs of the users on the channel. If we’re the only member, we send a channel message to the lobby channel on RTM to update everyone about the created room.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leaving the Call
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We leave the RTM and RTC video chat room channels but stay connected to the lobby channel on RTM to keep receiving updates. We update our state by clearing the &lt;code&gt;peerIds&lt;/code&gt; array, the &lt;code&gt;seniors&lt;/code&gt; array, and the &lt;code&gt;channelName&lt;/code&gt;. We also set &lt;code&gt;inCall&lt;/code&gt; as false and &lt;code&gt;inLobby&lt;/code&gt; as true to render the lobby UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rendering Our UI
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We define the render function for displaying buttons to display the status if we’re in a call or the lobby.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We use the &lt;code&gt;_renderRooms&lt;/code&gt; function to render a scroll view, which iterates over the rooms dictionary to show a list of created rooms with their member count. The user can tap any room to join it, which calls the &lt;code&gt;joinCall&lt;/code&gt; function. We also render a text input to let the user create a room that calls the same &lt;code&gt;joinCall&lt;/code&gt; function with that input.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We use the &lt;code&gt;_renderCall&lt;/code&gt; function to render the videos once we’re connected to a video chat room. We use the &lt;code&gt;RtcLocalView&lt;/code&gt; component from the SDK to render our own (local user’s) video. We use &lt;code&gt;RtcRemoteView&lt;/code&gt; inside a scroll view to render the videos of connected users using the UIDs stored in the &lt;code&gt;peerIds&lt;/code&gt; array. We also display a button to leave the room.&lt;/p&gt;

&lt;h2&gt;
  
  
  Permission.ts
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We’re exporting a helper function to request microphone permissions from the Android OS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Style.ts
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The Style.ts file contains the styling for the components.&lt;/p&gt;

&lt;h1&gt;
  
  
  What’s next?
&lt;/h1&gt;

&lt;p&gt;The same technique can be used to communicate other information, such as names of users connected, room description, and room title. We can even use the same mechanism to kick users off the call by sending an RTM message that, when evaluated, calls the leave channel method on the remote user’s device.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;You’ve seen how we can leverage the Agora RTM SDK to share information and dynamically create video chat rooms. You can refer to the &lt;a href="https://docs.agora.io/en/Video/API%20Reference/react_native/index.html"&gt;Agora React Native API Reference&lt;/a&gt; for methods that can help you quickly add more features to your next real-time engagement application.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Building a React Native Live Video Broadcasting App using Agora</title>
      <dc:creator>Ekaansh Arora</dc:creator>
      <pubDate>Tue, 02 Nov 2021 07:55:16 +0000</pubDate>
      <link>https://dev.to/ekaansharora/building-a-react-native-live-video-broadcasting-app-using-agora-1gff</link>
      <guid>https://dev.to/ekaansharora/building-a-react-native-live-video-broadcasting-app-using-agora-1gff</guid>
      <description>&lt;p&gt;Live video broadcasting has seen a range of uses from live shopping to live concerts. There are a lot of aspects to building a scalable, high-quality, live video streaming app. For example, maintaining low latency, load balancing, and managing thousands of users in the audience can be stressful while also maintaining cross-platform compatibility.&lt;/p&gt;

&lt;p&gt;There’s a really easy way to make this happen using the Agora React Native SDK. In this article, we’ll build a live broadcasting app that can have multiple broadcasters and host thousands of users by using the magic of the Agora Video SDK. We’ll go over the structure, setup, and execution of the app before diving into how it works. You can get a live broadcast going in a few simple steps within a matter of minutes.&lt;/p&gt;

&lt;p&gt;We’ll be using the &lt;a href="https://www.npmjs.com/package/react-native-agora/"&gt;Agora RTC SDK for React Native&lt;/a&gt; for the example below. I’m using v3.4.6 at the time of writing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an Agora account
&lt;/h2&gt;

&lt;p&gt;Create an account [&lt;a href="https://sso.agora.io/en/signup?utm_source=medium&amp;amp;utm_medium=blog&amp;amp;utm_campaign=building-a-react-native-live-video-broadcasting-app-using-agora"&gt;https://sso.agora.io/en/signup?utm_source=medium&amp;amp;utm_medium=blog&amp;amp;utm_campaign=building-a-react-native-live-video-broadcasting-app-using-agora&lt;/a&gt;) and log in to the dashboard. You can follow this guide for reference: &lt;a href="https://www.agora.io/en/blog/how-to-get-started-with-agora"&gt;https://www.agora.io/en/blog/how-to-get-started-with-agora&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigate to the Project List tab under the Project Management tab, and create a new project by clicking the blue Create button.&lt;br&gt;
Create a new project and retrieve the App ID. If you select App ID with a token, obtain a temporary token as well for your project. You can find a link to generate temporary tokens on the edit page. The temporary token will be used to authorize your requests while you’re developing the application.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Token authentication is recommended for all RTE apps running in production environments. For more information about token-based authentication in the Agora platform, see this guide: &lt;a href="https://docs.agora.io/en/Video/token?platform=All%20Platforms"&gt;https://docs.agora.io/en/Video/token?platform=All%20Platforms&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Structure of our example
&lt;/h2&gt;

&lt;p&gt;This is the structure of our application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── android
├── components
│ └── Permission.ts
│ └── Style.ts
├── ios
├── App.tsx
├── index.js
.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Let’s run the app
&lt;/h2&gt;

&lt;p&gt;You’ll need to have the LTS version of Node.js and NPM installed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make sure you’ve registered an Agora account, set up a project, and generated an App ID (and temporary token).&lt;/li&gt;
&lt;li&gt;Download and extract the ZIP file from the master branch.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm install&lt;/code&gt; to install the app dependencies in the unzipped directory.&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;./App.tsx&lt;/code&gt; and enter the App ID that we obtained from the Agora Console (&lt;code&gt;appId: ‘&amp;lt;YourAppIDHere&amp;gt;’&lt;/code&gt;). If you’re using tokens, enter your token and channel name as well.&lt;/li&gt;
&lt;li&gt;If you’re building for iOS, open a terminal and execute &lt;code&gt;cd ios &amp;amp;&amp;amp; pod install&lt;/code&gt;. You can then open &lt;code&gt;ios/&amp;lt;projectName&amp;gt;.xcworkspace&lt;/code&gt; file to open your project in XCode and build the app. (The iOS simulator does not support the camera. Use a physical device instead.)&lt;/li&gt;
&lt;li&gt;If you’re building for Android connect your device and execute npm run android to start the app. Wait for a few minutes for the app to build.&lt;/li&gt;
&lt;li&gt;Once you see the home screen on your mobile or emulator, click the Start Call button on the device.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it. You should have a video call going between the two devices. The app uses test as the channel name.&lt;/p&gt;
&lt;h2&gt;
  
  
  Getting to how it works
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Permission.ts
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
We’re exporting a function to request camera and microphone permissions from the OS on Android.&lt;/p&gt;

&lt;h3&gt;
  
  
  App.tsx
&lt;/h3&gt;

&lt;p&gt;The App.tsx file contains the core logic of our video call.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
We start by writing the import statements. Next, we have some constants for our App ID, token, and channel name.

&lt;p&gt;We define an interface for our application state containing isHost (a Boolean value to switch between audience and broadcaster; a host can both send and receive streams, whereas an audience can only receive streams), joinSucceed (a Boolean value to store if we’ve connected successfully), and peerIds (an array to store the UIDs of other users in the channel).&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
We define a class-based component, the _engine variable, which will store the instance of the RtcEngine class, which provides methods that can be invoked by our application to manage the live stream.

&lt;p&gt;In the constructor, we set our state variables and request permission for the camera and the mic on Android. When the component is mounted, we call the init function, which initializes the RTC engine using the App ID. It also enables the video by calling the enableVideo method on our engine instance.&lt;/p&gt;

&lt;p&gt;We set channelProfile as Live Broadcasting and clientRole based on our isHost state variable value.&lt;br&gt;
The init function also adds event listeners for various events in the live broadcast. For example, the UserJoined event gives us the UID of a user when they join the channel. We store this UID in our state.&lt;/p&gt;

&lt;p&gt;(If there are users connected to the channel before we joined, a UserJoined event is fired for each user after they successfully join the channel.)&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Next, we have the function toggleRole, which changes roles between audience and broadcaster. We have startCall and endCall to start and end the call. The toggleRole function updates the state and calls the setClientRole function with a role argument based on the state. The joinChannel method takes in a token, channel name, optional info, and an optional UID. (If you set UID to 0, the SDK automatically assigns a UID.)&lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
We define the render function for displaying buttons to start and end the call and to display our local video feed as well as the remote users’ video feeds. We define the _renderVideos function, which renders our video feeds.

&lt;p&gt;To display the local user’s video feed, we use the  component, which takes in channelId and renderMode (which can be used to fit the video inside a view or zoom to fill the view) as props. To display the remote user’s video feed, we use the  component from the SDK, which takes in the UID of the remote user along with channelId and renderMode. We map over the Remote users’ UIDs to display a video for each, using the peerIDs array.&lt;/p&gt;

&lt;h3&gt;
  
  
  Style.ts
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
The Style.ts file contains the styling for the components.

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That’s how easy it is to build a live video broadcasting app. You can refer to the &lt;a href="https://docs.agora.io/en/Video/API%20Reference/react_native/index.html"&gt;Agora React Native API Reference&lt;/a&gt; to see methods that can help you quickly add features like muting the camera and mic, setting video profiles, audio mixing, and much more.&lt;/p&gt;

&lt;p&gt;If you’re deploying your app to production, you can read more about how to use tokens in this &lt;a href="https://www.agora.io/en/blog/connecting-to-agora-with-tokens-react-native/"&gt;blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I invite you to join the &lt;a href="https://www.agora.io/en/join-slack/"&gt;Agora Developer Slack community&lt;/a&gt;. Feel free to ask any React Native questions in the &lt;code&gt;#react-native-help-me&lt;/code&gt; channel.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>javascript</category>
      <category>mobile</category>
      <category>livestreaming</category>
    </item>
    <item>
      <title>Connecting to Multiple Channels with Agora on React-Native</title>
      <dc:creator>Ekaansh Arora</dc:creator>
      <pubDate>Mon, 18 Oct 2021 11:33:57 +0000</pubDate>
      <link>https://dev.to/ekaansharora/connecting-to-multiple-channels-with-agora-on-react-native-3hg8</link>
      <guid>https://dev.to/ekaansharora/connecting-to-multiple-channels-with-agora-on-react-native-3hg8</guid>
      <description>&lt;p&gt;Since the release of v3.0.0 of Agora’s SDK for React-Native users can now join an unlimited number of channels at the same time. But you can publish your own camera feed to only one channel at a time.&lt;/p&gt;

&lt;p&gt;This ability can be really handy in the case of multiple breakout rooms, where you can both send and receive video from a primary room while also receiving videos from secondary rooms.&lt;/p&gt;

&lt;p&gt;We’ll be using the &lt;a href="https://www.npmjs.com/package/@zhigang1992/react-native-agora"&gt;Agora RTC SDK for React Native&lt;/a&gt; for our example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before diving into how it works, let’s look at a few key points
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  We’ll use the SDK to connect to the first channel and join a video call normally. We’ll be streaming our video as well as receiving video from other users on the channel.&lt;/li&gt;
&lt;li&gt;  Next, we’ll join a second channel to receive video streams from all the users on that channel. Note that users on channel 2 will not be able to receive our video.&lt;/li&gt;
&lt;li&gt;  The two channels are separate: users on channel 1 and channel 2 don’t see each other. We can extend this functionality to join as many channels as required.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Structure of our example
&lt;/h1&gt;

&lt;p&gt;This is the structure of the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── android  
├── components  
│ └── Permission.ts
│ └── Style.ts  
├── ios  
├── App.tsx  
.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h1&gt;
  
  
  Download the source
&lt;/h1&gt;

&lt;p&gt;If you want to jump to the code and try it out for yourself, you can look at the readme for steps on how to run the app. The code is open source and available on &lt;a href="https://github.com/EkaanshArora/Agora-RN-Multi-Channel"&gt;GitHub&lt;/a&gt;. The app uses channel-1 and channel-2 as the channel names.&lt;/p&gt;

&lt;p&gt;When you run the app, you’ll see two buttons: one to join and one to end the call. When you click start call, you should see your video in the top row, which contains videos from channel 1. The bottom row contains videos from channel 2.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This guide does not implement token authentication which is recommended for all RTE apps running in production environments. For more information about token based authentication within the Agora platform please refer to this guide: &lt;a href="https://docs.agora.io/en/Video/token?platform=All%20Platforms"&gt;https://docs.agora.io/en/Video/token?platform=All%20Platforms&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  How the App Works
&lt;/h1&gt;
&lt;h2&gt;
  
  
  App.tsx
&lt;/h2&gt;

&lt;p&gt;App.tsx will be the entry point into the app. We’ll have all our code in this file:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;We start by writing the import statements. Next, we define an interface for our application state containing the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;appId&lt;/code&gt;: Our Agora App ID&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;token&lt;/code&gt;: Token generated to join the channel&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;channelNameOne&lt;/code&gt;: Name for channel 1&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;channelNameTwo&lt;/code&gt;: Name for channel 2&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;joinSucceed&lt;/code&gt;: Boolean value to store if we’ve connected successfully&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;peerIdsOne&lt;/code&gt;: Array to store the UIDs of other users in channel 1&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;peerIdsTwo&lt;/code&gt;: Array to store the UIDs of other users in channel 2&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
We define a class-based component: the &lt;code&gt;_rtcEngine&lt;/code&gt; variable will store the instance of the &lt;code&gt;RtcEngine&lt;/code&gt; class, and the &lt;code&gt;_channel&lt;/code&gt; variable will store the instance of the &lt;code&gt;RtcChannel&lt;/code&gt; class, which we can use to access the SDK functions.

&lt;p&gt;In the constructor, we set our state variables and request permission for recording audio on Android. (We use a helper function from &lt;code&gt;permission.ts&lt;/code&gt;, as described below.) When the component is mounted, we call the init  function, which initializes the RTC engine and RTC channel. When the component unmounts, we destroy our engine and channel instances.&lt;/p&gt;
&lt;h2&gt;
  
  
  RTC initialization
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We use the App ID to create our engine instance. The engine instance will be used to connect to channel 1, where we both send and receive the video. We also create our channel instance using the name of our second channel. The channel instance will be used only to receive videos from channel 2.&lt;/p&gt;

&lt;p&gt;The RTC triggers a userJoined event for each user present when we join the channel and for each new user who joins after. The userOffline event is triggered when a user leaves the channel. We use event listeners on _engine and _channel to store and maintain our peerIdsOne and peerIdsTwo arrays containing the UIDs for users on both the channels.&lt;/p&gt;

&lt;p&gt;We also attach a listener for joinChannelSuccess to update our state variable which is used to render our UI while we’re in the call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functions for our buttons
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;startCall&lt;/code&gt; function joins both the channels using the joinChannel method.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;endCall&lt;/code&gt; function leaves both the channels using the leaveChannel method and updates the state.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;destroy&lt;/code&gt; function destroys the instances of our engine and channel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rendering our UI
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We define the render function for displaying buttons to start and end the call and to display user videos from both channels.&lt;/p&gt;

&lt;p&gt;We define a &lt;code&gt;_renderVideos&lt;/code&gt; function to render the videos from both our channels using the &lt;code&gt;_renderRemoteVideosOne&lt;/code&gt; and &lt;code&gt;_renderRemoteVideosTwo&lt;/code&gt; functions for channel 1 and channel 2. Each function contains scrollViews to hold videos from the channel. We use the UIDs stored in peerId arrays to render remote users’ videos by passing them to the &lt;code&gt;RtcRemoteView.SurfaceView&lt;/code&gt; component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Permission.ts
&lt;/h2&gt;

&lt;p&gt;We’re exporting a helper function to request microphone permissions from the Android OS.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Style.ts
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Style.ts&lt;/code&gt; file contains the styling for the components.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;That’s how we can build a video call app that can connect to two channels simultaneously. You can refer to the &lt;a href="https://docs.agora.io/en/Video/API%20Reference/react_native/index.html"&gt;Agora React Native API Reference&lt;/a&gt; to see methods that can help you quickly add many features like muting the mic, setting audio profiles and audio mixing.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>reactnative</category>
      <category>tutorial</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Building a Live Audio Streaming React Native App with Agora</title>
      <dc:creator>Ekaansh Arora</dc:creator>
      <pubDate>Tue, 12 Oct 2021 09:36:55 +0000</pubDate>
      <link>https://dev.to/ekaansharora/building-a-live-audio-streaming-react-native-app-with-agora-3be2</link>
      <guid>https://dev.to/ekaansharora/building-a-live-audio-streaming-react-native-app-with-agora-3be2</guid>
      <description>&lt;p&gt;Live audio streaming is increasingly popular across a wide range of uses, from live podcasts and interviews to live music performances. The possibilities are endless once you have a few users engaging with an audience in real-time.&lt;/p&gt;

&lt;p&gt;There’s an easy way to accomplish live audio streaming using the Agora React Native SDK. In this tutorial, we’ll walk through building a live audio broadcasting app that can have multiple broadcasters and host thousands of users by utilizing the Agora Audio SDK. We’ll go over the structure, setup, and execution of the app before diving into the code. The open-source code is available &lt;a href="https://github.com/EkaanshArora/Agora-RN-Audio-Broadcast"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ll be using &lt;a href="https://www.npmjs.com/package/react-native-agora/"&gt;Agora RTC SDK for React Native&lt;/a&gt; for the example. I’m using v3.2.2 at the time of writing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an Agora Account
&lt;/h2&gt;

&lt;p&gt;Sign up at &lt;a href="https://console.agora.io/"&gt;https://console.agora.io/&lt;/a&gt; and log in to the dashboard.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Nwk3KVBa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/337/1%2ApAkpJsnCJZx1VVzFw2TFiw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Nwk3KVBa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/337/1%2ApAkpJsnCJZx1VVzFw2TFiw.png" alt="Agora Console"&gt;&lt;/a&gt;&lt;br&gt;
Navigate to the Project List tab under the Project Management tab and create a project by clicking the blue Create button.&lt;/p&gt;

&lt;p&gt;Create a project and retrieve the App ID. (When prompted to use App ID + Certificate, select only App ID.) The App ID will be used to authorize your requests while you’re developing the application, without generating tokens.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This guide does not implement token authentication which is recommended for all RTE apps running in production environments. For more information about token-based authentication within the Agora platform please refer to this guide: &lt;a href="https://docs.agora.io/en/Video/token?platform=All%20Platforms"&gt;https://docs.agora.io/en/Video/token?platform=All%20Platforms&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Structure of Our Example
&lt;/h2&gt;

&lt;p&gt;This is the structure of the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── android
├── components
│ └── Permission.ts
│ └── Style.ts
├── ios
├── App.tsx
├── index.js
.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Running the App
&lt;/h2&gt;

&lt;p&gt;You’ll need to have a recent version of Node.js and NPM installed;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make sure you’ve set up an Agora account, set up a project, and generated an App ID (as discussed above).&lt;/li&gt;
&lt;li&gt;Download and extract the ZIP file from the master branch.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm install&lt;/code&gt; to install the app dependencies in the unzipped directory.&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;./App.tsx&lt;/code&gt; and enter the App ID as &lt;code&gt;appId: YourAppIdHere&lt;/code&gt; in the state declaration.&lt;/li&gt;
&lt;li&gt;If you’re building for iOS, open a terminal and execute cd ios &amp;amp;&amp;amp; pod install.&lt;/li&gt;
&lt;li&gt;Connect your device, and run npx react-native run-android / npx react-native run-ios to start the app. Give it a few minutes to build the app and install it on your device.&lt;/li&gt;
&lt;li&gt;Once you see the home screen on your mobile device (or emulator), click the start call button on the device.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it. You should have an audio broadcast going between the two devices.&lt;/p&gt;

&lt;p&gt;The app uses &lt;code&gt;channel-x&lt;/code&gt; as the channel name.&lt;/p&gt;
&lt;h3&gt;
  
  
  Before we dive into the code, let’s get a few basics out of the way:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;We’ll use the Agora RTC (Real-time Communication) SDK to connect to a channel and join an audio call.&lt;/li&gt;
&lt;li&gt;We can have multiple users broadcasting to a channel. All users as an audience on that channel can listen to the broadcasters.&lt;/li&gt;
&lt;li&gt;The audience can dynamically switch to a broadcaster role.&lt;/li&gt;
&lt;li&gt;The Agora RTC SDK uses unique IDs (UIDs) for each user. To associate these UIDs with a username, we’ll use the Agora RTM (Real-time Messaging) SDK to signal the username to others on the call. We’ll discuss how it’s done below.
Let’s take a look at how the code works:&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  App.tsx
&lt;/h2&gt;

&lt;p&gt;App.tsx will be the entry point into the app. We’ll have all our code in this file. When you open the app, there will be a username field with three buttons: to join the call, end the call, and toggle our user role between broadcaster and audience.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;We start by writing the used import statements. Next, we define an interface for our application state containing the following:&lt;br&gt;
&lt;code&gt;appId&lt;/code&gt;: our Agora App ID&lt;br&gt;
&lt;code&gt;token&lt;/code&gt;: token generated to join the channel&lt;br&gt;
&lt;code&gt;isHost&lt;/code&gt;: boolean value to switch between audience and broadcaster&lt;br&gt;
&lt;code&gt;channelName&lt;/code&gt;: name for the channel&lt;br&gt;
&lt;code&gt;joinSucceed&lt;/code&gt;: boolean value to store if we’ve connected successfully&lt;br&gt;
&lt;code&gt;rtcUid&lt;/code&gt;: local user’s UID on joining the RTC channel&lt;br&gt;
&lt;code&gt;myUsername&lt;/code&gt;: local user’s name to log in to RTM&lt;br&gt;
&lt;code&gt;usernames&lt;/code&gt;: a dictionary associating RTC UIDs of remote users to their usernames that we’ll get using RTM&lt;br&gt;
&lt;code&gt;peerIds&lt;/code&gt;: an array to store the UIDs of other users in the channel&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We define a class-based component: the &lt;code&gt;_rtcEngine&lt;/code&gt; variable will store the instance of the &lt;code&gt;RtcEngine&lt;/code&gt; class, and the &lt;code&gt;_rtmEngine&lt;/code&gt; variable will store the instance of the &lt;code&gt;RtmEngine&lt;/code&gt; class, which we can use to access the SDK functions.&lt;/p&gt;

&lt;p&gt;In the constructor, we set our state variables and request permission for recording audio on Android. (We use a helper function from &lt;code&gt;permission.ts&lt;/code&gt;, as described below.) When the component is mounted, we call the &lt;code&gt;initRTC&lt;/code&gt; and &lt;code&gt;initRTM&lt;/code&gt; functions, which initialize the RTC and RTM engines using the App ID. When the component unmounts, we destroy our engine instances.&lt;/p&gt;

&lt;h2&gt;
  
  
  RTC Initialization
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
We use the App ID to create our engine instance. Next, we set &lt;code&gt;channelProfile&lt;/code&gt; to Live Broadcasting and &lt;code&gt;clientRole&lt;/code&gt; based on our &lt;code&gt;isHost&lt;/code&gt; state variable value.

&lt;p&gt;The RTC triggers a &lt;code&gt;userJoined&lt;/code&gt; event for each user present when we join the channel and for each new user who joins later. The &lt;code&gt;userOffline&lt;/code&gt; event is triggered when a user leaves the channel. We use event listeners to sync our &lt;code&gt;peerIds&lt;/code&gt; array.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Audience members don’t trigger the userJoined/userOffline event.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  RTM Initialization
&lt;/h2&gt;

&lt;p&gt;We’re using RTM to send our username to other usernames on the call. And this is how we associate our usernames with our RTC UID&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When a user joins a channel, we send a message to all channel members as &lt;code&gt;UID:Username&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;On receiving a channel message, all users add the key-value pair to their username dictionary.&lt;/li&gt;
&lt;li&gt;When a new user joins, all members on the channel send a peer message to that user in the same schema &lt;code&gt;UID:Username&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;On receiving peer messages, we do the same (add the key-value pair to the dictionary) and update our usernames.
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

Following our plan, we attach event listeners with functions to populate and update usernames on &lt;code&gt;channelMessageReceived&lt;/code&gt; (broadcast message to channel), &lt;code&gt;messageReceived&lt;/code&gt; (peer message), and &lt;code&gt;channelMemberJoined&lt;/code&gt; events. We also create a client on the engine using the same App ID.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Functions for Our Buttons
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
The &lt;code&gt;toggleRole&lt;/code&gt; function updates the state and calls the &lt;code&gt;setClientRole&lt;/code&gt; function with the correct argument based on the state.&lt;br&gt;
The &lt;code&gt;startCall&lt;/code&gt; function checks if a username is entered. It then joins the RTC channel. It also logs in to RTM, joins the channel, and sends the channel message for the username, as we discussed before.&lt;br&gt;
The &lt;code&gt;endCall&lt;/code&gt; function leaves the RTC channel, sends a message that is used to remove the username from our remote users dictionary, and then leaves and logs out of RTM.

&lt;h2&gt;
  
  
  Rendering Our UI
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
We define the render function for displaying buttons to start and end the call as well as to toggle roles. We define a function &lt;code&gt;_renderUsers&lt;/code&gt; that renders a list of all broadcasters and audience members.

&lt;h2&gt;
  
  
  Permission.ts
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
We’re exporting a helper function to request microphone permissions from the Android OS.

&lt;h2&gt;
  
  
  Style.ts
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
The Style.ts file contains the styling for the components.

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That’s how easy it is to build a live audio streaming app. For more information about building applications using Agora SDKs, take a look at the &lt;a href="https://docs.agora.io/en/Video/landing-page?platform=React%20Native"&gt;Agora Video Call Quickstart Guide&lt;/a&gt; and &lt;a href="https://docs.agora.io/en/Video/API%20Reference/react_native/index.html"&gt;Agora API Reference&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I invite you to join the &lt;a href="https://www.agora.io/en/join-slack/"&gt;Agora Developer Slack community&lt;/a&gt;. You can ask any questions about Agora in the &lt;code&gt;#react-native-help-me&lt;/code&gt; channel.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>tutorial</category>
      <category>mobile</category>
      <category>javascript</category>
    </item>
    <item>
      <title>React Native: Streaming Agora Cloud-Recording HLS Videos from an S3 Bucket</title>
      <dc:creator>Ekaansh Arora</dc:creator>
      <pubDate>Mon, 11 Oct 2021 10:03:34 +0000</pubDate>
      <link>https://dev.to/ekaansharora/react-native-streaming-agora-cloud-recording-hls-videos-from-an-s3-bucket-4n6l</link>
      <guid>https://dev.to/ekaansharora/react-native-streaming-agora-cloud-recording-hls-videos-from-an-s3-bucket-4n6l</guid>
      <description>&lt;p&gt;In a &lt;a href="https://www.agora.io/en/blog/cloud-recording-for-react-native-video-chat-using-agora/"&gt;previous blog&lt;/a&gt; post, we looked at how to add Agora cloud recording to a video chat application for storing the recordings in an Amazon S3 bucket. Here, we’ll go over how to fetch and playback the recorded videos in a React Native application.&lt;/p&gt;

&lt;p&gt;We’ve updated the &lt;a href="https://github.com/EkaanshArora/Agora-RN-Record-Playback"&gt;app&lt;/a&gt; and the &lt;a href="https://github.com/EkaanshArora/Agora-Cloud-Recording-Example"&gt;back end&lt;/a&gt; from the last blog post to bring everything together. If you just want the demo, you can deploy the back end and build the app from the links provided.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An Agora developer account (see How to Get Started)&lt;/li&gt;
&lt;li&gt;An Amazon AWS account&lt;/li&gt;
&lt;li&gt;A Heroku account or another service to deploy the back end&lt;/li&gt;
&lt;li&gt;Understanding of React Native&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Agora Setup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a project&lt;/strong&gt;: Once you have an Agora account, click the Project Management tab in the console. Click the Create button. Enter a name for your project. Select Secured Mode while creating the project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable cloud recording&lt;/strong&gt;: Click the View usage button and select the option to enable cloud recording.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get app credentials&lt;/strong&gt;: Copy the App ID and the App Certificate from the same page to a text file. We’ll use these later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get customer credentials&lt;/strong&gt;: Visit the RESTful API page and click the Add Secret button. Copy the Customer ID and the Customer Secret to a text file.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  AWS Setup
&lt;/h2&gt;

&lt;p&gt;Once you’ve created an AWS account, we need to create an Amazon S3 bucket to store our video recordings and an IAM user to access our bucket. If you have already completed this setup, you can skip this section.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to your &lt;a href="https://console.aws.amazon.com/iam/home#/users"&gt;AWS IAM Console&lt;/a&gt; and create a user. Add the AmazonS3FullAccess policy with Programmatic Access. Copy your AWS Access Key and Secret Key to the text file.&lt;/li&gt;
&lt;li&gt;Create an Amazon &lt;a href="https://s3.console.aws.amazon.com/s3/home"&gt;S3 bucket&lt;/a&gt;:
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VyGfNr5i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/1%2A2LAlWLeGZNd7QGibCKFEbA.png" alt="aws screenshot"&gt;
Choose a name for your bucket and copy it to a text file. We’ll use this text file later. Allow public access to stream media from your bucket by deselecting the block all public access check box. Click the Create Bucket button.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: With the URL for your recording, anyone on the internet can view it. We’ll discuss how to make the recording secure at the end of the post.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We’ll also need the region number for the selected AWS region. Go to this &lt;a href="https://docs.agora.io/en/cloud-recording/cloud_recording_api_rest?platform=RESTful#a-namestorageconfigacloud-storage-configuration"&gt;table&lt;/a&gt;, click the Amazon S3 tab, and note your region number. For example, if you’re using the US_EAST_1 region, your bucket number is 0.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the bucket policy.
To make files accessible by all users, we’ll add a bucket policy. Go to the Permissions tab in your newly created bucket and add this policy:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "Version": "2012-10-17",
    "Id": "Policy1620917655085",
    "Statement": [
        {
            "Sid": "Stmt1620917653925",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::agora-rec123/*"
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Deploying Our Back End
&lt;/h2&gt;

&lt;p&gt;Before deploying our back end, we need the following variables. (It’s time to use our text file.) We’ll be using the Heroku one-click deploy to make it super simple to get our back end up and running. You can use any other service as well.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: We’ve updated the back end, so if you’re using the back end from the previous post, you should update it now.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;APP_ID=
APP_CERTIFICATE=
RECORDING_VENDOR=
RECORDING_REGION=
BUCKET_NAME=
BUCKET_ACCESS_KEY=
BUCKET_ACCESS_SECRET=
CUSTOMER_ID=
CUSTOMER_CERTIFICATE=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Note: RECORDING_VENDOR=1 for AWS. Click this link for more information.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Create an account on Heroku if you haven’t done so already.&lt;/li&gt;
&lt;li&gt;Click this link to use the Heroku one-click deploy.&lt;/li&gt;
&lt;li&gt;Enter your variables and click the Deploy App button at the bottom of the page.&lt;/li&gt;
&lt;li&gt;Wait a few minutes. Once the deployment is complete, save your back-end URL in a text file, which we’ll use in the app.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Building Our App
&lt;/h2&gt;

&lt;p&gt;We’ll start from the app we developed in the last post, which lets you take part in group video calls and record them. I’ve refactored the app to move all the video call and recording components to &lt;code&gt;./components/Call.tsx&lt;/code&gt;. We’ll start with a new file: &lt;code&gt;./components/PlayRecording.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
We’ll use the Video component from react-native-video for HLS playback. We take in the back-end URL, App ID, and channel name as props to our PlayRecording component. We define an interface for our state. tracks will contain an array of URLs for each m3u8 file. currentTrack is the index of the URL we’re playing. statusMsg holds a string to display the current status of the video player.&lt;br&gt;&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
We define our component and our initial state. In the &lt;code&gt;componentDidMount&lt;/code&gt; we perform a GET request to the &lt;code&gt;/api/get/recordingUrls/&amp;lt;ChannelName&amp;gt;&lt;/code&gt; route of our back-end server. We get the response JSON and update the &lt;code&gt;tracks&lt;/code&gt; state array.&lt;br&gt;&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
In our render method, we’re returning a list of tracks wrapped in &lt;code&gt;TouchableOpacity&lt;/code&gt; using a &lt;code&gt;ScrollView&lt;/code&gt;. When a track is selected, we update the &lt;code&gt;currentTrack&lt;/code&gt; state with the track index.&lt;br&gt;&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
We use the &lt;code&gt;Video&lt;/code&gt; component with the source set as the URL we want to play (&lt;code&gt;currentTrack&lt;/code&gt; index of our &lt;code&gt;tracks&lt;/code&gt; array). We have event handlers to update our &lt;code&gt;statusMsg&lt;/code&gt;. We also display the &lt;code&gt;statusMsg&lt;/code&gt; in a &lt;code&gt;Text&lt;/code&gt; component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it back together
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
We use the &lt;code&gt;PlayRecording&lt;/code&gt; component in our &lt;code&gt;App.tsx&lt;/code&gt; along with the Call component to put everything back together.

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Security Consideration&lt;/strong&gt;: As we discussed, with our current configuration all the recordings stored on the S3 bucket are public so that the React Native client can access them. Before we use the app in production, it’s important to set access control for our videos. Once we get our users authenticated, we can issue them access to the files, while keeping the files private for everyone else. You can find more information &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html"&gt;here&lt;/a&gt; and &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-overview.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You can find more information about cloud recording &lt;a href="https://docs.agora.io/en/cloud-recording/landing-page?platform=RESTful"&gt;here&lt;/a&gt;. If you’re starting out with the Agora SDKs, take a look at the &lt;a href="https://docs.agora.io/en/Video/landing-page?platform=React%20Native"&gt;Agora Video Call Quickstart Guide&lt;/a&gt; and this &lt;a href="https://www.agora.io/en/blog/how-to-build-a-react-native-video-calling-app-using-agora/"&gt;blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And I invite you to join the &lt;a href="https://www.agora.io/en/join-slack/"&gt;Agora Developer Slack community&lt;/a&gt;. Feel free to ask any React Native questions in the &lt;code&gt;#react-native-help-me&lt;/code&gt; channel and cloud recording questions in the &lt;code&gt;#cloud-recording-help-me&lt;/code&gt; channel.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Building a Video Calling App Using the Agora SDK on Expo (React Native)</title>
      <dc:creator>Ekaansh Arora</dc:creator>
      <pubDate>Fri, 08 Oct 2021 07:16:40 +0000</pubDate>
      <link>https://dev.to/ekaansharora/building-a-video-calling-app-using-the-agora-sdk-on-expo-react-native-38ij</link>
      <guid>https://dev.to/ekaansharora/building-a-video-calling-app-using-the-agora-sdk-on-expo-react-native-38ij</guid>
      <description>&lt;p&gt;With the &lt;a href="https://dev.toasd"&gt;release&lt;/a&gt; of Expo SDK 42, it’s now possible to customize the native runtime of your apps using custom development clients. It took me a while to wrap my head around all the new concepts, but I’m really excited!&lt;/p&gt;

&lt;p&gt;Essentially, this means that we can now use libraries that contain native code (like Swift and Kotlin) with Expo without having to resort to the bare workflow (which would take away most of the Expo benefits and ease of use). The new experience is really easy to set up and start using. You can find more information in this &lt;a href="https://blog.expo.dev/expo-sdk-42-579aee2348b6"&gt;official blog&lt;/a&gt; and the &lt;a href="https://docs.expo.dev/clients/getting-started/"&gt;Expo docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this isn’t:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You cannot use the Expo Go app for testing the code with native modules. This means you’ll need to build and distribute your app to anyone who wants to test it.&lt;/li&gt;
&lt;li&gt;If you want to build for iOS without having access to a Mac, you’ll need to use EAS Build or an alternative cloud service.&lt;/li&gt;
&lt;li&gt;This is going to be slightly more involved than the Expo JS-only experience. You’ll need to set up Android Studio and/or XCode.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en/"&gt;Node.js LTS release&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/"&gt;Git&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://facebook.github.io/watchman/docs/install#buildinstall"&gt;Watchman (brew install watchman)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://yarnpkg.com/getting-started/install"&gt;Yarn (npm i -g yarn)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.expo.dev/get-started/installation/"&gt;Expo CLI (npm i -g expo-cli)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Android Studio/XCode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Installing Node.js and Git would depend on your operating system. To install Yarn and Expo, you can simply run &lt;code&gt;npm i -g yarn expo-cli&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a new project
&lt;/h2&gt;

&lt;p&gt;To create an Expo project, we’ll use the Expo CLI. Open a new terminal and execute &lt;code&gt;expo init&lt;/code&gt; to bring up the CLI that will guide you through the process. Let’s leverage the typescript template by selecting the blank TS option.&lt;br&gt;
You can run native platform code in React Native with the use of native modules. With the new release of Expo dev clients, it’s now possible to use native modules without leaving the managed workflow.&lt;br&gt;
To make native modules (libraries that use native platform code) work with Expo, we’ll install the Expo dev client by running &lt;code&gt;yarn add expo-dev-client&lt;/code&gt; in the project directory created by the Expo CLI.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: We can’t use the Expo Go app to run the project, because we’re bundling native code. We’ll get around this by building a custom client.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Installing native modules
&lt;/h2&gt;

&lt;p&gt;Let’s install the native dependency: the Agora React Native SDK. In a terminal, execute &lt;code&gt;yarn add react-native-agora&lt;/code&gt;. You don’t need any extra configuration for the Agora SDK. If your library requires modifying the native runtime, you can read more about how to write a custom plug-in &lt;a href="https://docs.expo.dev/clients/getting-started/#customizing-your-runtime"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For the app demo, let’s install the Agora React Native UIKit. &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i3JOwpme--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/AgoraIO-Community"&gt;
        AgoraIO-Community
      &lt;/a&gt; / &lt;a href="https://github.com/AgoraIO-Community/ReactNative-UIKit"&gt;
        ReactNative-UIKit
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A React Native package to simply integrate Agora Video Calling or Live Video Streaming to your app with just a few lines of code.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;
It is a pure JavaScript library that helps us build a video calling app with ten lines of code. You can execute &lt;code&gt;yarn add agora-rn-uikit&lt;/code&gt; to install it. It relies on the Agora React Native SDK for its functionality.

&lt;p&gt;We can now start writing the app:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;To get better errors and logs, I recommend adding &lt;code&gt;import ‘expo-dev-client’;&lt;/code&gt; to the top of your &lt;code&gt;App.tsx&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;To build a video calling app, all we need is the &lt;code&gt;AgoraUIKit&lt;/code&gt; high-level component from the UIKit library. We can pass in the &lt;code&gt;appId&lt;/code&gt; and &lt;code&gt;channel&lt;/code&gt; to the &lt;code&gt;RtcProps&lt;/code&gt;. We can use a state variable to render the call UI that we can update using the &lt;code&gt;EndCall&lt;/code&gt; callback. The AgoraUIKit component is rendered when the &lt;code&gt;videoCall&lt;/code&gt; state is true.&lt;/p&gt;

&lt;p&gt;You can read more about how the UIKit works &lt;a href="https://www.agora.io/en/creating-a-react-native-video-chat-app-in-a-few-lines-of-code-using-agora-uikit/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run your app
&lt;/h2&gt;

&lt;p&gt;Now for the moment of truth: let’s try running the app. To build a custom client, we can execute &lt;code&gt;expo run:android&lt;/code&gt; or &lt;code&gt;expo run:ios&lt;/code&gt; in a terminal. If you’re building for iOS, use a physical device to test since camera functionality is not available in the iOS simulator. You will be prompted to select a bundle ID (a unique identifier for your app). You can enter a custom ID or use the prefilled option.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: If you’re building for iOS, you’ll need to add camera and microphone permissions text to your &lt;code&gt;info.plist&lt;/code&gt; file using XCode:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sFEfIP3C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2000/0%2AFU5yVts-2Sq0PON-" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sFEfIP3C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2000/0%2AFU5yVts-2Sq0PON-" alt="XCode Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once that’s done, you’ll need to wait a couple of minutes for the CLI to build the custom client and install it on your device. You’ll see the project directory get populated with iOS and Android folders. You can now run the Expo dev server by executing &lt;code&gt;expo start --dev-client&lt;/code&gt; in the project directory. Once the app loads, you can then scan the server QR code or select it from the list in the app. Your app should load from metro just like a normal React Native app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The Expo SDK offers a lot of developer-friendly features on top of React Native. In the past, we’d use the bare workflow. If our app needed any native modules, however, it would take away some of the benefits. Plus, setting it up was a task. Using custom clients, we can leverage the power of Expo with the flexibility of native modules.&lt;/p&gt;

&lt;p&gt;You can read my blog about the React Native UIKit &lt;a href="https://www.agora.io/en/creating-a-react-native-video-chat-app-in-a-few-lines-of-code-using-agora-uikit/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Resources
&lt;/h2&gt;

&lt;p&gt;For more information about building applications using Agora SDKs, take a look at the &lt;a href="https://docs.agora.io/en/Video/landing-page?platform=React%20Native"&gt;Agora Video Call Quickstart Guide&lt;/a&gt; and &lt;a href="https://docs.agora.io/en/Video/API%20Reference/react_native/index.html"&gt;Agora API Reference&lt;/a&gt;. You can also take a look at the &lt;a href="https://github.com/AgoraIO-Community/ReactNative-UIKit"&gt;UIKit GitHub Repo&lt;/a&gt;.&lt;br&gt;
I invite you to join the &lt;a href="https://www.agora.io/en/join-slack/"&gt;Agora Developer Slack community&lt;/a&gt;. You can ask any questions about Agora in the &lt;code&gt;#react-native-help-me&lt;/code&gt; channel.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>mobile</category>
    </item>
  </channel>
</rss>
