Avicus Delacroix
Posted on March 9, 2021
The pandemic changed us all. Working and studying remotely, we craved live communications and seeing our friends and colleagues in person. Maybe that's why a new social network, Clubhouse, has gathered more than 6 million people in less than a year.
Clubhouse is an all-new type of social networking. No texting at all, communicate only by voice. All the communication happens in so-called "rooms", which can be open for everyone or private. The room's owner (moderator) decides who can talk, and the listeners can "raise a hand" to indicate that they want to ask a question.
However, Clubhouse has its limitations. For now, it's only available for iOS users, and to join, you need to receive an invitation from an existing user. But what if you are an Android user?
You can wait until they release an Android or desktop version, or you can make your own Clubhouse, with blackjack better security, voice recording, AI, and support for any platform. And Voximplant will help you.
In this article, you’ll see how to create a Clubhouse-like audio room with Voximplant's Web SDK, so clients can use a common browser as a client.
Please note that Voximplant supports multiple SDKs, from Web, iOS, and Android to React Native, Flutter, and even Unity. Imagine, you can embed an audio (or video) chat into your game design
Set up VoxEngine
VoxEngine is a cloud platform to enable serverless communications. Let's create a room. Log into your account (or create one) and create a new application. Then create a user for authorization and a new scenario.
First import the conference module. Then implement user disconnecting:
require(Modules.Conference)
let owner = null;
const onEndpointDisconnected = (event)=>{
const members = conference.getList();
if(members.length === 1){
VoxEngine.terminate();
return;
}
}
Then implement permissions check:
const checkPermissions = ({call,headers}) =>{
return new Promise((resolve)=>{
setTimeout(()=>{resolve(true)},500);
});
}
Implement room creation and adding a new user:
let logURL = ''; // for debug reason
let conference = null;
VoxEngine.addEventListener(AppEvents.Started, event => {
logURL = event.logURL;
conference = VoxEngine.createConference({hd_audio:true});
})
VoxEngine.addEventListener(AppEvents.CallAlerting, async event => {
const permissions = await checkPermissions(event);
if(permissions) {
event.call.addEventListener(CallEvents.Disconnected, onEndpointDisconnected);
event.call.answer();
conference.add({
call: event.call,
displayName: event.headers['X-Name'],
mode: "FORWARD",
direction: "BOTH",
scheme: event.scheme
});
if(conference.getList().length === 1){
owner = conference.getList()[0].id();
conference.getList()[0].getCall().sendMessage('owner');
}
conference.get(owner).getCall()
.sendMessage(conference.getList().length);)
} else {
event.call.hangup({'X-Reason':'DENIED'});
}
});
The first part is done. Now let's create a client.
Set up the client
As I decided to make an example with Web SDK, my client will be an HTML-page. I'll hide the control buttons until the SDK initialization.
<!DOCTYPE html>
<html lang="en">
<head>
<style>
.hidden {
display: none !important;
}
</style>
<meta charset="UTF-8">
<title>The demo</title>
</head>
<body>
<div id="btns" class="hidden">
<p id="myname">Avi</p>
<button id="viewer">Join as listener</button>
<button id="speaker">Join as speaker</button>
<button id="leave" disabled>Leave</button>
</div>
<div id="audio"></div>
<h3>Current speakers <span id="countSpeakers">0</span></h3>
<div id="endpoints"></div>
</body>
<script src="*****"></script>
An interesting part. Let's initialize our SDK in the tag and show the control buttons if the initialization is successful.<br> </p> <div class="highlight"><pre class="highlight javascript"><code><span class="o"><</span><span class="nx">script</span><span class="o">></span> <span class="c1">// sdk init</span> <span class="kd">const</span> <span class="nx">sdk</span> <span class="o">=</span> <span class="nx">VoxImplant</span><span class="p">.</span><span class="nx">getInstance</span><span class="p">();</span> <span class="kd">let</span> <span class="nx">user</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">user*****</span><span class="dl">'</span><span class="p">;</span> <span class="kd">const</span> <span class="nx">init</span> <span class="o">=</span> <span class="k">async</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="k">await</span> <span class="nx">sdk</span><span class="p">.</span><span class="nx">init</span><span class="p">({</span> <span class="na">showDebugInfo</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="na">serverIp</span><span class="p">:</span> <span class="dl">'</span><span class="s1">url*****</span><span class="dl">'</span> <span class="p">});</span> <span class="k">await</span> <span class="nx">sdk</span><span class="p">.</span><span class="nx">connect</span><span class="p">();</span> <span class="k">await</span> <span class="nx">sdk</span><span class="p">.</span><span class="nx">login</span><span class="p">(</span><span class="s2">`</span><span class="p">${</span><span class="nx">user</span><span class="p">}</span><span class="s2">@app**.acc**.voximplant.com`</span><span class="p">,</span> <span class="dl">'</span><span class="s1">pass*****</span><span class="dl">'</span><span class="p">);</span> <span class="p">}</span> <span class="nx">init</span><span class="p">().</span><span class="nx">then</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">btns</span><span class="dl">'</span><span class="p">).</span><span class="nx">classList</span><span class="p">.</span><span class="nx">remove</span><span class="p">(</span><span class="dl">'</span><span class="s1">hidden</span><span class="dl">'</span><span class="p">);</span> <span class="p">});</span> </code></pre></div> <p></p> <p>Create some necessary constants. I will get the user name from an HTML-tag with id=”myname”. Then let's define when each button is displayed:<br> </p> <div class="highlight"><pre class="highlight javascript"><code><span class="kd">let</span> <span class="nx">currentCall</span><span class="p">;</span> <span class="kd">let</span> <span class="nx">currentRole</span><span class="p">;</span> <span class="kd">let</span> <span class="nx">countSpeakers</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="kd">const</span> <span class="nx">confNumber</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">Test room</span><span class="dl">'</span><span class="p">;</span> <span class="kd">const</span> <span class="nx">speakerBtn</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">speaker</span><span class="dl">'</span><span class="p">);</span> <span class="kd">const</span> <span class="nx">viewerBtn</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">viewer</span><span class="dl">'</span><span class="p">);</span> <span class="kd">const</span> <span class="nx">leaveBtn</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">leave</span><span class="dl">'</span><span class="p">);</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">myname</span><span class="dl">'</span><span class="p">).</span><span class="nx">innerText</span> <span class="o">=</span> <span class="nx">myName</span><span class="p">;</span> <span class="kd">let</span> <span class="nx">setRole</span> <span class="o">=</span> <span class="p">(</span><span class="nx">role</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">currentRole</span> <span class="o">=</span> <span class="nx">role</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="nx">role</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">speaker</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span> <span class="nx">speakerBtn</span><span class="p">.</span><span class="nx">disabled</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span> <span class="nx">leaveBtn</span><span class="p">.</span><span class="nx">disabled</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span> <span class="nx">viewerBtn</span><span class="p">.</span><span class="nx">disabled</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="nx">role</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">viewer</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span> <span class="nx">speakerBtn</span><span class="p">.</span><span class="nx">disabled</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span> <span class="nx">leaveBtn</span><span class="p">.</span><span class="nx">disabled</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span> <span class="nx">viewerBtn</span><span class="p">.</span><span class="nx">disabled</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="nx">role</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">start</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span> <span class="nx">speakerBtn</span><span class="p">.</span><span class="nx">disabled</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span> <span class="nx">viewerBtn</span><span class="p">.</span><span class="nx">disabled</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span> <span class="nx">leaveBtn</span><span class="p">.</span><span class="nx">disabled</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div> <p></p> <p>Handle <a href="https://voximplant.com/docs/references/websdk/voximplant/call#hangup">leaving the conversation</a>:<br> </p> <div class="highlight"><pre class="highlight javascript"><code><span class="kd">let</span> <span class="nx">endCall</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="k">if</span><span class="p">(</span><span class="nx">currentCall</span> <span class="o">&&</span> <span class="nx">currentCall</span><span class="p">.</span><span class="nx">state</span><span class="p">()</span> <span class="o">!==</span> <span class="dl">'</span><span class="s1">ENDED</span><span class="dl">'</span><span class="p">)</span> <span class="p">{</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">endpoints</span><span class="dl">'</span><span class="p">).</span><span class="nx">innerText</span> <span class="o">=</span> <span class="dl">''</span><span class="p">;</span> <span class="nx">currentCall</span><span class="p">.</span><span class="nx">hangup</span><span class="p">();</span> <span class="nx">setRole</span><span class="p">(</span><span class="dl">'</span><span class="s1">start</span><span class="dl">'</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div> <p></p> <p>Then <a href="https://voximplant.com/docs/references/websdk/voximplant/endpointevents#remotemediaadded">adding</a> and <a href="https://voximplant.com/docs/references/websdk/voximplant/endpointevents#remotemediaremoved">removing a user</a> to/from a conversation:<br> </p> <div class="highlight"><pre class="highlight javascript"><code><span class="kd">let</span> <span class="nx">onEndpointAdded</span> <span class="o">=</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">warn</span><span class="p">(</span><span class="dl">'</span><span class="s1">Endpoint added</span><span class="dl">'</span><span class="p">,</span> <span class="nx">e</span><span class="p">.</span><span class="nx">endpoint</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span> <span class="kd">const</span> <span class="nx">nameTable</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">endpoints</span><span class="dl">'</span><span class="p">);</span> <span class="kd">let</span> <span class="nx">p</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="dl">'</span><span class="s1">p</span><span class="dl">'</span><span class="p">);</span> <span class="nx">p</span><span class="p">.</span><span class="nx">id</span> <span class="o">=</span> <span class="nx">e</span><span class="p">.</span><span class="nx">endpoint</span><span class="p">.</span><span class="nx">id</span><span class="p">;</span> <span class="nx">p</span><span class="p">.</span><span class="nx">innerText</span> <span class="o">=</span> <span class="s2">`Name: </span><span class="p">${</span><span class="nx">e</span><span class="p">.</span><span class="nx">endpoint</span><span class="p">.</span><span class="nx">displayName</span><span class="p">}</span><span class="s2">, id: </span><span class="p">${</span><span class="nx">e</span><span class="p">.</span><span class="nx">endpoint</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span> <span class="nx">nameTable</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="nx">p</span><span class="p">);</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">countSpeakers</span><span class="dl">'</span><span class="p">).</span><span class="nx">innerText</span> <span class="o">=</span> <span class="nx">countSpeakers</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">e</span><span class="p">.</span><span class="nx">endpoint</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="nx">VoxImplant</span><span class="p">.</span><span class="nx">EndpointEvents</span><span class="p">.</span><span class="nx">RemoteMediaAdded</span><span class="p">,</span> <span class="p">(</span><span class="nx">ev</span><span class="p">)</span><span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">warn</span><span class="p">(</span><span class="dl">'</span><span class="s1">RemoteMediaAdded</span><span class="dl">'</span><span class="p">,</span> <span class="nx">ev</span><span class="p">.</span><span class="nx">mediaRenderer</span><span class="p">);</span> <span class="kd">const</span> <span class="nx">nodeCall</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">audio</span><span class="dl">'</span><span class="p">);</span> <span class="nx">ev</span><span class="p">.</span><span class="nx">mediaRenderer</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="nx">nodeCall</span><span class="p">);</span> <span class="p">})</span> <span class="nx">e</span><span class="p">.</span><span class="nx">endpoint</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="nx">VoxImplant</span><span class="p">.</span><span class="nx">EndpointEvents</span><span class="p">.</span><span class="nx">RemoteMediaRemoved</span><span class="p">,</span> <span class="p">(</span><span class="nx">ev</span><span class="p">)</span><span class="o">=></span><span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">warn</span><span class="p">(</span><span class="s2">`Endpoint </span><span class="p">${</span><span class="nx">e</span><span class="p">.</span><span class="nx">endpoint</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span><span class="s2"> media removed </span><span class="p">${</span><span class="nx">ev</span><span class="p">.</span><span class="nx">mediaRenderer</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span> <span class="p">})</span> <span class="c1">// ENDPOINT REMOVED</span> <span class="nx">e</span><span class="p">.</span><span class="nx">endpoint</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="nx">VoxImplant</span><span class="p">.</span><span class="nx">EndpointEvents</span><span class="p">.</span><span class="nx">Removed</span><span class="p">,</span> <span class="p">(</span><span class="nx">ev</span><span class="p">)</span><span class="o">=></span><span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">warn</span><span class="p">(</span><span class="s2">`Endpoint </span><span class="p">${</span><span class="nx">e</span><span class="p">.</span><span class="nx">endpoint</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span><span class="s2"> removed`</span><span class="p">);</span> <span class="kd">let</span> <span class="nx">removeP</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">endpoint</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span> <span class="nx">nameTable</span><span class="p">.</span><span class="nx">removeChild</span><span class="p">(</span><span class="nx">removeP</span><span class="p">);</span> <span class="p">})</span> <span class="p">}</span> </code></pre></div> <p></p> <p>Handle the Leave button and some necessary events:<br> </p> <div class="highlight"><pre class="highlight javascript"><code><span class="kd">const</span> <span class="nx">setCall</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">leaveBtn</span><span class="p">.</span><span class="nx">onclick</span> <span class="o">=</span> <span class="nx">endCall</span><span class="p">;</span> <span class="nx">currentCall</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="nx">VoxImplant</span><span class="p">.</span><span class="nx">CallEvents</span><span class="p">.</span><span class="nx">EndpointAdded</span><span class="p">,</span> <span class="nx">onEndpointAdded</span><span class="p">);</span> <span class="nx">currentCall</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="nx">VoxImplant</span><span class="p">.</span><span class="nx">CallEvents</span><span class="p">.</span><span class="nx">MessageReceived</span><span class="p">,</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">warn</span><span class="p">(</span><span class="dl">'</span><span class="s1">MessageReceived</span><span class="dl">'</span><span class="p">,</span> <span class="nx">e</span><span class="p">.</span><span class="nx">text</span><span class="p">);</span> <span class="p">});</span> <span class="c1">//handle connection</span> <span class="nx">currentCall</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="nx">VoxImplant</span><span class="p">.</span><span class="nx">CallEvents</span><span class="p">.</span><span class="nx">Connected</span><span class="p">,</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">warn</span><span class="p">(</span><span class="s2">`Call connected successfully`</span><span class="p">);</span> <span class="p">});</span> <span class="c1">//other call event listeners</span> <span class="nx">currentCall</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="nx">VoxImplant</span><span class="p">.</span><span class="nx">CallEvents</span><span class="p">.</span><span class="nx">Disconnected</span><span class="p">,</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">warn</span><span class="p">(</span><span class="s2">`Call disconnected`</span><span class="p">);</span> <span class="nx">endCall</span><span class="p">();</span> <span class="p">});</span> <span class="nx">currentCall</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="nx">VoxImplant</span><span class="p">.</span><span class="nx">CallEvents</span><span class="p">.</span><span class="nx">Failed</span><span class="p">,</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">warn</span><span class="p">(</span><span class="s2">`Call failed`</span><span class="p">);</span> <span class="nx">endCall</span><span class="p">();</span> <span class="p">});</span> <span class="p">}</span> </code></pre></div> <p></p> <p>And handle the role buttons (Speaker or Listener):<br> </p> <div class="highlight"><pre class="highlight javascript"><code><span class="nx">speakerBtn</span><span class="p">.</span><span class="nx">onclick</span> <span class="o">=</span> <span class="k">async</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">endpoints</span><span class="dl">'</span><span class="p">).</span><span class="nx">innerText</span> <span class="o">=</span> <span class="dl">''</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="nx">currentCall</span><span class="p">)</span> <span class="p">{</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">endpoints</span><span class="dl">'</span><span class="p">).</span><span class="nx">innerText</span> <span class="o">=</span> <span class="dl">''</span><span class="p">;</span> <span class="k">await</span> <span class="nx">currentCall</span><span class="p">.</span><span class="nx">hangup</span><span class="p">();</span> <span class="p">}</span> <span class="nx">setTimeout</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">setRole</span><span class="p">(</span><span class="dl">'</span><span class="s1">speaker</span><span class="dl">'</span><span class="p">);</span> <span class="nx">currentCall</span> <span class="o">=</span> <span class="nx">sdk</span><span class="p">.</span><span class="nx">callConference</span><span class="p">({</span> <span class="na">number</span><span class="p">:</span> <span class="nx">confNumber</span><span class="p">,</span> <span class="na">extraHeaders</span><span class="p">:</span> <span class="p">{</span><span class="dl">'</span><span class="s1">X-Name</span><span class="dl">'</span><span class="p">:</span> <span class="nx">myName</span><span class="p">}</span> <span class="p">});</span> <span class="nx">setCall</span><span class="p">();</span> <span class="p">},</span> <span class="mi">300</span><span class="p">)</span> <span class="p">}</span> <span class="nx">viewerBtn</span><span class="p">.</span><span class="nx">onclick</span> <span class="o">=</span> <span class="k">async</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="k">if</span><span class="p">(</span><span class="nx">currentCall</span><span class="p">)</span> <span class="p">{</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">endpoints</span><span class="dl">'</span><span class="p">).</span><span class="nx">innerText</span> <span class="o">=</span> <span class="dl">''</span><span class="p">;</span> <span class="k">await</span> <span class="nx">currentCall</span><span class="p">.</span><span class="nx">hangup</span><span class="p">();</span> <span class="p">}</span> <span class="nx">setTimeout</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">setRole</span><span class="p">(</span><span class="dl">'</span><span class="s1">viewer</span><span class="dl">'</span><span class="p">);</span> <span class="nx">currentCall</span> <span class="o">=</span> <span class="nx">sdk</span><span class="p">.</span><span class="nx">joinAsViewer</span><span class="p">(</span><span class="nx">confNumber</span><span class="p">);</span> <span class="nx">setCall</span><span class="p">();</span> <span class="p">},</span> <span class="mi">300</span><span class="p">)</span> <span class="p">}</span> <span class="o"><</span><span class="sr">/script</span><span class="err">> </span><span class="o"><</span><span class="sr">/html</span><span class="err">> </span></code></pre></div> <p></p> <p><strong>Done</strong>. Now we have a working room with two roles (Speaker and Listener) simple button controls and a list of active speakers. All we need to do to make it a complete app is to make a decent interface and add some user/room management with databases and search.</p> <p>And do not forget that the functionality of the Voximplant engine goes far beyond this: you can schedule a voice room to record if you're unable to join due to a scheduling conflict, you can add messages if you need, you can even create interactive voice menus with speech synthesis and recognition, which can be lots of fun.</p>
Posted on March 9, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.