<html>
<head>
<meta name="description" content="Select media devices for call">
<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>Recording devices:</div>
<div><select id="recordingDevices" size="3" onchange="selectRecordingDevice()" style="width:200px"></select></div>
<div>Video devices:</div>
<div><select id="videoDevices" size="3" onchange="selectVideoDevice()" style="width:200px"></select></div>
<div>Playback devices:</div>
<div><select id="playbackDevices" size="3" onchange="selectPlaybackDevice()" style="width:200px"></select></div>
<div>Ringing devices:</div>
<div><select id="ringingDevices" size="3" onchange="selectRingingDevice()" style="width:200px"></select></div>
</section>
<section>
<input type="email" id="peerUser" placeholder="Callee's Circuit email" value="circuitsdk01@gmail.com"/>
<button onclick="call()" id="callButton">Call</button>
<button onclick="endCall()" id="endCallButton" style="display: none">End call</button>
</section>
<section id="output">
<div>Connection state: <span id="logonState">Disconnected</span></div>
<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 id="videoContainer" style="display:none">
<video id="localVideo" height="200px" autoplay="true"></video>
<video id="remoteVideo" height="200px" autoplay="true"></video><br>
</div>
</section>
</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: Select media devices for call',
description: 'Set the mic, camera, headset, etc for the call. Also supports changing the device during the call.',
apiMethods: ['makeCall', 'endCall', 'setMediaDevices'],
prerequisites: []
});
// Local variables
var _localUser;
var _call;
//Circuit.logger.setLevel(Circuit.Enums.LogLevel.Debug);
navigator.mediaDevices.enumerateDevices().then(devices => {
devices.filter(d => d.kind === 'audioinput').forEach(d => {
let opt = document.createElement('option');
opt.value = d.deviceId;
opt.innerHTML = d.label;
recordingDevices.appendChild(opt);
});
recordingDevices.selectedIndex = 0;
devices.filter(d => d.kind === 'videoinput').forEach(d => {
let opt = document.createElement('option');
opt.value = d.deviceId;
opt.innerHTML = d.label;
videoDevices.appendChild(opt);
});
videoDevices.selectedIndex = 0;
devices.filter(d => d.kind === 'audiooutput').forEach(d => {
let opt = document.createElement('option');
opt.value = d.deviceId;
opt.innerHTML = d.label;
playbackDevices.appendChild(opt);
});
playbackDevices.selectedIndex = 0;
devices.filter(d => d.kind === 'audiooutput').forEach(d => {
let opt = document.createElement('option');
opt.value = d.deviceId;
opt.innerHTML = d.label;
ringingDevices.appendChild(opt);
});
ringingDevices.selectedIndex = 0;
});
function selectRecordingDevice() {
print(`Selected recording device is: ${recordingDevices.options[recordingDevices.selectedIndex].text}`);
if (client.setMediaDevices) {
client.setMediaDevices({recording: recordingDevices.options[recordingDevices.selectedIndex].value});
} else {
Circuit.RtcSessionController.recordingDevices = [{
id: audioDevices.options[playbackDevices.selectedIndex].value
}];
}
}
function selectVideoDevice() {
print(`Selected video device is: ${videoDevices.options[videoDevices.selectedIndex].text}`);
if (client.setMediaDevices) {
client.setMediaDevices({video: videoDevices.options[videoDevices.selectedIndex].value});
} else {
Circuit.RtcSessionController.videoDevices = [{
id: videoDevices.options[videoDevices.selectedIndex].value
}];
}
}
function selectPlaybackDevice() {
print(`Selected playback device is: ${playbackDevices.options[playbackDevices.selectedIndex].text}`);
if (client.setMediaDevices) {
client.setMediaDevices({playback: playbackDevices.options[playbackDevices.selectedIndex].value});
} else {
Circuit.RtcSessionController.playbackDevices = [{
id: playbackDevices.options[playbackDevices.selectedIndex].value
}];
}
}
function selectRingingDevice() {
print(`Selected ringing device is: ${ringingDevices.options[ringingDevices.selectedIndex].text}`);
if (client.setMediaDevices) {
client.setMediaDevices({ringing: ringingDevices.options[ringingDevices.selectedIndex].value});
} else {
Circuit.RtcSessionController.ringingDevices = [{
id: ringingDevices.options[ringingDevices.selectedIndex].value
}];
}
}
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';
localVideo.srcObject = null;
remoteVideo.srcObject = null;
remoteAudio.srcObject = null;
videoContainer.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 = '';
// Set local video stream
localVideo.srcObject = _call.localVideo;
// Enable video checkbox
if (_call.isEstablished) {
remoteAudio.srcObject = _call.remoteAudioStream;
// Set remote video stream
if (_call.participants && _call.participants[0] && remoteVideo.srcObject != _call.participants[0].videoStream) {
remoteVideo.srcObject = _call.participants[0].videoStream;
}
}
videoContainer.style.display = _call.localMediaType.video || _call.participants.some(p => p.videoStream) ? '' : 'none';
}
function addClientEventListeners() {
client.addEventListener('connectionStateChanged', evt => {
logonState.textContent = evt.state;
});
client.addEventListener('callStatus', evt => {
if (_call && _call.callId === evt.call.callId) {
print('Received callStatus event - call = ', evt.call);
setCallUI(evt.call);
}
});
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: videoDevices.selectedIndex >= 0};
client.makeCall(peerUser.value, mediaType)
.then(setCallUI)
.catch(err => {
alert('Error initiating a call with ' + peerUser.value + '. ' + 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. |