Skip to content

Instantly share code, notes, and snippets.

@kwindla
Created September 4, 2020 03:20
Show Gist options
  • Save kwindla/1e8bd83e0a964a21d8913da178df54d4 to your computer and use it in GitHub Desktop.
Save kwindla/1e8bd83e0a964a21d8913da178df54d4 to your computer and use it in GitHub Desktop.
Daily.co video call API local audio track recorder example
<html>
<head>
<title>record local audio</title>
<script src="./daily-js-pluot-core/dist/daily-iframe.js"></script>
</head>
<body onload="join()">
<div id="buttons" style="width: 50%; float: left">
</div>
<div id="videos" style="width: 50%; float: right">
</div>
<script>
const ROOM_URL = 'https://DAILY-CO-TEAM-NAME.daily.co/ROOM_NAME';
const AUDIO_CHUNK_SIZE_IN_SECONDS = 2;
async function join() {
try {
window.callObject = DailyIframe.createCallObject({ url: ROOM_URL });
// for recording of local audio
window.callObject.on("track-started", localAudioTrackStarted);
window.callObject.on("track-stopped", localAudioTrackStopped);
// for normal display/playback of video audio tracks in UI
window.callObject.on("track-started", trackStarted);
window.callObject.on("track-stopped", trackStopped);
window.callObject.on("left-meeting", leftMeeting);
await callObject.join();
} catch (e) {
console.error(e);
}
}
async function localAudioTrackStarted(e) {
if (!(e &&
e.participant &&
e.participant.local &&
e.track &&
e.track.kind === 'audio')) {
return;
}
console.log('starting local audio recorder', e);
window.audioRecorder = new ExampleRecorder({ track: e.track });
}
async function localAudioTrackStopped(e) {
if (!(e &&
e.participant &&
e.participant.local &&
e.track &&
e.track.kind === 'audio')) {
return;
}
window.audioRecorder.stopRecording();
window.audioRecorder = null;
}
class ExampleRecorder {
constructor({ track }) {
this.startRecording(track);
}
async startRecording(track) {
if (!track || track.kind !== 'audio') {
console.log('need an audio track in order to record');
return;
}
try {
this.mediaRecorder = new MediaRecorder(
new MediaStream([ track ]),
{
mimeType: "audio/webm; codecs=opus",
audioBitsPerSecond: 60 * 1000,
}
);
this.mediaRecorder.ondataavailable = this.onData.bind(this);
this.mediaRecorder.onstop = this.onStop.bind(this);
this.mediaRecorder.onerror = this.errorHandler.bind(this);
this.mediaRecorder.start(AUDIO_CHUNK_SIZE_IN_SECONDS * 1000);
} catch (e) {
console.error(e);
}
}
async stopRecording() {
this.mediaRecorder.stop();
}
async onData(blobEvent) {
let data = await blobEvent.data.arrayBuffer();
console.log('new data to handle ... DO SOMETHING WITH THE DATA HERE',
data);
}
async onStop() {
console.log('recorder stopped ... clean up if necessary');
}
errorHandler(e) {
console.error('recorder error', e);
}
}
//
// ---- general utility functions to display video and playback audio ----
//
function trackStarted(e) {
let vidsContainer = document.getElementById("videos");
if (e.track && e.track.kind === "video") {
let isScreenTrack = e.track === e.participant.screenVideoTrack;
let vid = findVideoForParticipant(e.participant.session_id, isScreenTrack);
if (!vid) {
vid = document.createElement("video");
vid.session_id = e.participant.session_id;
vid.is_screen_track = isScreenTrack;
vid.style.width = "100%";
vid.autoplay = true;
vid.muted = true;
vid.playsInline = true;
vidsContainer.appendChild(vid);
}
vid.srcObject = new MediaStream([e.track]);
} else if (e.track && e.track.kind === "audio") {
let aud = findAudioForParticipant(e.participant.session_id);
if (!aud) {
aud = document.createElement("audio");
aud.session_id = e.participant.session_id;
if (e.participant && e.participant.local) {
console.log("local audio track ... not playing locally");
aud.muted = true;
} else {
aud.autoplay = true;
}
vidsContainer.appendChild(aud);
}
aud.srcObject = new MediaStream([e.track]);
}
}
function trackStopped(e) {
let el =
findVideoForTrack(e.track && e.track.id) ||
findAudioForTrack(e.track && e.track.id);
if (el) {
el.remove();
}
}
function findVideoForParticipant(session_id, isScreenTrack) {
for (const vid of document.getElementsByTagName("video")) {
if (
vid.session_id === session_id &&
vid.is_screen_track === isScreenTrack
) {
return vid;
}
}
}
function findVideoForTrack(trackId) {
for (const vid of document.getElementsByTagName("video")) {
if (
vid.srcObject &&
vid.srcObject.getTracks().find((t) => t.id === trackId)
) {
return vid;
}
}
}
function findAudioForParticipant(session_id) {
for (const aud of document.getElementsByTagName("audio")) {
if (aud.session_id === session_id) {
return aud;
}
}
}
function findAudioForTrack(trackId) {
for (const aud of document.getElementsByTagName("audio")) {
if (
aud.srcObject &&
aud.srcObject.getTracks().find((t) => t.id === trackId)
) {
return aud;
}
}
}
function leftMeeting(e) {
document.getElementById("videos").innerHTML = "";
}
async function aTimeout(ms) {
return new Promise((resolve) => setTimeout(() => resolve(), ms));
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment