<html>
<head>
<meta name="description" content="Upgrade Direct Call to Conference">
<title>Circuit JS SDK</title>
<script src="https://unpkg.com/circuit-sdk@beta"></script>
<script src="https://rawgit.com/circuit/js-sdk/master/jsbin-template.js"></script>
<link rel="stylesheet" href="https://rawgit.com/circuit/js-sdk/master/jsbin-template.css">
</head>
<body>
<div id="template"></div>
<div id="main" style="display:none">
<section>
<div>
<input type="email" id="peerUser" placeholder="Callee's Circuit email" value="circuitsdk01@gmail.com"/>
<button onclick="call()" id="callButton">Call</button>
</div>
<div id="addParticipantContainer" style="display: none">
<input type="email" id="peerUser2" placeholder="3rd participant email" value="circuitsdk02@gmail.com"/>
<button onclick="addParticipant()">Add participant</button>
</div>
<div>
<button onclick="endCall()" id="endCallButton" style="display: none">End call</button>
</div>
</section>
<section id="output">
<div>Call state: <span id="callState"></span></div>
<div>Media: <span id="media"></span></div>
<div>Conversation ID: <span id="convId"></span></div>
<div>Call ID: <span id="callId"></span></div>
</div>
<audio id="remoteAudio" autoplay="autoplay"></audio>
</body>
</html>
/*jshint esnext: true */
// Create client instance
const client = new Circuit.Client({
domain: jsBinTpl.domain, // read domain from url
client_id: jsBinTpl.client_id, // get client_id for domain
scope: 'ALL'
});
// Template for Circuit JSBin examples. Builds generic part of page incl. login button.
const {logonButton, logoutButton, print} = jsBinTpl.init(client, template, {
title: 'Circuit JS SDK: Upgrade Direct Call to Conference',
description: 'Start a direct call with another Circuit user, then add a 3rd user which automatically creates a group conversation and moves the call to the new conversation',
apiMethods: ['addParticipant', 'answerCall', 'makeCall', 'endCall'],
prerequisites: []
});
// Local variables
var _localUser;
var _call;
Circuit.logger.setLevel(Circuit.Enums.LogLevel.Debug);
logonButton.addEventListener('click', () => {
!_localUser && addClientEventListeners();
client.logon()
.then(user => {
print(`Successfully authenticated as ${user.displayName}`)
_localUser = user;
})
.catch(err => {
print(err);
client.removeAllListeners();
});
});
logoutButton.addEventListener('click', () => {
client.logout()
.catch(print);
});
function resetCallUI() {
callState.textContent = '';
media.textContent = '';
callId.textContent = '';
convId.textContent = '';
callButton.style.display = '';
endCallButton.style.display = 'none';
remoteAudio.srcObject = null;
addParticipantContainer.style.display = 'none';
}
function setCallUI(call) {
_call = call;
convId.textContent = _call.convId;
callState.textContent = _call.state;
callId.textContent = _call.callId;
media.textContent = (_call.activeMediaType.audio ? 'audio' : '') + (_call.activeMediaType.video ? '+video' : '');
callButton.style.display = 'none';
endCallButton.style.display = '';
if (_call.isEstablished) {
remoteAudio.srcObject = _call.remoteAudioStream;
}
addParticipantContainer.style.display = _call.isEstablished ? '' : 'none';
}
function addClientEventListeners() {
client.addEventListener('callStatus', evt => {
if (_call && _call.callId === evt.call.callId) {
print('Received callStatus event - call = ', evt.call);
setCallUI(evt.call);
}
});
client.addEventListener('callIncoming', evt => {
print('Received callIncoming event - call = ', evt.call);
setCallUI(evt.call);
// Automatically answer the call
var mediaType = {audio: true, video: enableVideo.checked};
client.answerCall(_call.callId, mediaType).then(() => {
print('Call has been answered')
}).catch(err => {
print('Failed to answer call. ', err)
});
});
client.addEventListener('callEnded', evt => {
if (_call && _call.callId === evt.call.callId) {
print('Received callEnded event - call = ', evt.call);
_call = null;
resetCallUI();
}
});
}
function call() {
if (_call) {
return;
}
if (!client || !_localUser) { return alert('Caller is not logged in'); }
if (!peerUser.value) { return alert('Callee email missing'); }
var mediaType = {audio: true, video: false};
client.makeCall(peerUser.value, mediaType)
.then(setCallUI)
.catch(err => {
alert(`Error initiating a call with ${peerUser.value}. Error: ${err}`);
print(err);
});
}
function updateCall(conv) {
if (!conv) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
client.findCall(conv.rtcSessionId)
.then(call => {
_call = call;
resolve();
})
.catch(reject);
});
}
function addParticipant() {
client.getUserByEmail(peerUser2.value)
.then(user => client.addParticipant(_call.convId, [user.userId], true))
.then(updateCall)
.catch(err => {
alert(`Error addding user to call. Error: ${err}`);
print(err);
});
}
function endCall() {
if (_call) {
client.endCall(_call.callId).then(() => {
print('Successfully ended call');
_call = null;
resetCallUI();
});
}
}
Output
300px
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |