Skip to content

Commit

Permalink
feat: Record and send audio via Chrome microphone (#1996)
Browse files Browse the repository at this point in the history
Co-authored-by: Rohin Bhargava <[email protected]>
  • Loading branch information
namanagar and RohinBhargava authored Jan 15, 2025
1 parent 6692418 commit 1c203cb
Show file tree
Hide file tree
Showing 19 changed files with 776 additions and 221 deletions.
1 change: 1 addition & 0 deletions fern/apis/fdr/definition/api/v1/read/type.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ types:
Base64Type:
properties:
default: optional<base64>
mimeType: optional<string>

DateType:
properties:
Expand Down
1 change: 1 addition & 0 deletions fern/apis/fdr/definition/api/v1/register/type.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ types:
Base64Type:
properties:
default: optional<base64>
mimeType: optional<string>

DateType:
properties:
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/fern-docs/bundle/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vercel
2 changes: 2 additions & 0 deletions packages/fern-docs/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"jotai-location": "^0.5.5",
"jsonpath": "^1.1.1",
"launchdarkly-react-client-sdk": "^3.6.0",
"lucide-react": "^0.460.0",
"mdx-bundler": "^10.0.2",
"mermaid": "^11.2.1",
"moment": "^2.30.1",
Expand Down Expand Up @@ -122,6 +123,7 @@
"unist-util-visit": "^5.0.0",
"url-join": "5.0.0",
"use-memo-one": "^1.1.3",
"webm-duration-fix": "^1.0.4",
"zod": "^3.23.8"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { FernButton, FernButtonGroup } from "@fern-docs/components";
import { Download, Octagon, Play } from "lucide-react";
import { useEffect, useRef, useState } from "react";

interface PlaygroundAudioControlsProps {
audioUrl: string | null;
fileName?: string;
}

export function PlaygroundAudioControls({
audioUrl,
fileName = "recording.webm",
}: PlaygroundAudioControlsProps) {
const [isPlaying, setIsPlaying] = useState(false);
const [currentTime, setCurrentTime] = useState(0);
const [duration, setDuration] = useState(0);
const [isLoaded, setIsLoaded] = useState(false);
const audioRef = useRef<HTMLAudioElement | null>(null);

useEffect(() => {
if (audioRef.current) {
audioRef.current.onended = () => setIsPlaying(false);
audioRef.current.onloadedmetadata = () => {
const audioDuration = audioRef.current?.duration;
if (audioDuration && !isNaN(audioDuration) && isFinite(audioDuration)) {
setDuration(Math.round(audioDuration));
setIsLoaded(true);
}
};
audioRef.current.ontimeupdate = () => {
const currentTime = audioRef.current?.currentTime;
if (currentTime && !isNaN(currentTime) && isFinite(currentTime)) {
setCurrentTime(Math.round(currentTime));
}
};
}
}, []);

const formatTime = (seconds: number) => {
const mins = Math.floor(seconds / 60)
.toString()
.padStart(2, "0");
const secs = (seconds % 60).toString().padStart(2, "0");
return `${mins}:${secs}`;
};

const handlePlayPause = async () => {
if (!audioRef.current || !audioUrl) return;

if (isPlaying) {
audioRef.current.pause();
audioRef.current.currentTime = 0;
setCurrentTime(0);
} else {
await audioRef.current.play();
}
setIsPlaying(!isPlaying);
};

const handleDownload = () => {
if (!audioUrl) return;
const a = document.createElement("a");
a.href = audioUrl;
a.download = fileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
};

if (!audioUrl) return null;

return (
<div className="flex items-center gap-2">
<audio ref={audioRef} src={audioUrl} preload="metadata" />
{isLoaded && (
<span className="font-mono text-xs">
{`${formatTime(currentTime)}/${formatTime(duration)}`}
</span>
)}
<FernButtonGroup>
<FernButton
icon={isPlaying ? <Octagon /> : <Play />}
onClick={handlePlayPause}
size="small"
variant="minimal"
disabled={!audioUrl}
/>
<FernButton
icon={<Download />}
onClick={handleDownload}
size="small"
variant="minimal"
disabled={!audioUrl}
/>
</FernButtonGroup>
</div>
);
}
Loading

0 comments on commit 1c203cb

Please sign in to comment.