Skip to content

Commit

Permalink
Cleanup; guard against browser support
Browse files Browse the repository at this point in the history
  • Loading branch information
fgwt202412 committed Dec 15, 2024
1 parent 46898df commit 7b6c7be
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 26 deletions.
28 changes: 15 additions & 13 deletions website/src/components/McapRecordingDemo/McapRecordingDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ import {
toProtobufTime,
} from "./Recorder";
import {
recordAudioStream,
startAudioStream,
CompressedAudioData,
startAudioCapture,
supportsOpusEncoding,
} from "./audioCapture";
import {
CompressedVideoFrame,
Expand Down Expand Up @@ -164,6 +164,7 @@ export function McapRecordingDemo(): JSX.Element {
const { data: h265Support } = useAsync(supportsH265Encoding);
const { data: vp9Support } = useAsync(supportsVP9Encoding);
const { data: av1Support } = useAsync(supportsAV1Encoding);
const { data: opusSupport } = useAsync(supportsOpusEncoding);

const canStartRecording =
recordMouse ||
Expand Down Expand Up @@ -294,7 +295,6 @@ export function McapRecordingDemo(): JSX.Element {
recordH265,
recordVP9,
recordAV1,
recordVP9,
recording,
videoStarted,
recordJpeg,
Expand Down Expand Up @@ -346,7 +346,7 @@ export function McapRecordingDemo(): JSX.Element {
});

return () => {
cleanup();
cleanup?.();
};
}, [addAudioData, enableMicrophone, recordOpus, audioStream, recording]);

Expand Down Expand Up @@ -488,16 +488,18 @@ export function McapRecordingDemo(): JSX.Element {
/>
Camera (JPEG)
</label>
<label>
<input
type="checkbox"
checked={recordOpus}
onChange={(event) => {
setRecordOpus(event.target.checked);
}}
/>
Microphone (Opus)
</label>
{opusSupport === true && (
<label>
<input
type="checkbox"
checked={recordOpus}
onChange={(event) => {
setRecordOpus(event.target.checked);
}}
/>
Microphone (Opus)
</label>
)}
{!hasMouse && (
<label>
<input
Expand Down
69 changes: 56 additions & 13 deletions website/src/components/McapRecordingDemo/audioCapture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,39 @@ export function startAudioStream({
};
}

/**
* Determine whether required Web Audio APIs are supported.
*
* Capture uses MediaStreamTrackProcessor and AudioEncoder to
* read and encode audio frames.
*
* MediaStreamTrackProcessor: https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrackProcessor#browser_compatibility
* AudioEncoder: https://developer.mozilla.org/en-US/docs/Web/API/AudioEncoder#browser_compatibility
*
* As of 2024-12-15, Chrome and Edge have support
*/
const supportsMediaCaptureTransformAndWebCodecs = (): boolean => {
return "MediaStreamTrackProcessor" in window && "AudioEncoder" in window;
};

const DEFAULT_OPUS_CONFIG: AudioEncoderConfig = {
codec: "opus",
sampleRate: 48000,
numberOfChannels: 1,
};

/**
* Determine whether AudioEncoder can be used to encode audio with Opus.
*/
export const supportsOpusEncoding = async (): Promise<boolean> => {
if (!supportsMediaCaptureTransformAndWebCodecs()) {
return false;
}

const support = await AudioEncoder.isConfigSupported(DEFAULT_OPUS_CONFIG);
return support.supported === true;
};

type CompressedAudioFormat = "opus";
type CompressedAudioType = "key" | "delta";
export type CompressedAudioData = {
Expand Down Expand Up @@ -112,27 +145,36 @@ export function startAudioCapture({
stream,
onAudioData,
onError,
}: AudioCaptureParams): () => void {
const framePool: ArrayBuffer[] = [];
}: AudioCaptureParams): (() => void) | undefined {
if (!enableOpus) {
onError(new Error("Invariant: expected Opus encoding to be enabled"));
return undefined;
}

if (!supportsMediaCaptureTransformAndWebCodecs()) {
onError(
new Error(
"Audio capture not supported: MediaStreamTrackProcessor and AudioEncoder not supported in browser",
),
);
return undefined;
}

const track = stream.getAudioTracks()[0];
if (!track) {
onError(new Error("Invariant: expected audio track"));
return () => {
// no op
};
onError(new Error("Invariant: expected audio track from stream"));
return undefined;
}

const settings = track.getSettings();

const trackProcessor = new MediaStreamTrackProcessor({
// TODO: Don't assert
track: stream.getAudioTracks()[0]!,
track,
});

const settings = track.getSettings();
const framePool: ArrayBuffer[] = [];

const encoder = new AudioEncoder({
output: (chunk) => {
console.log(chunk);
let buffer = framePool.pop();
if (!buffer || buffer.byteLength < chunk.byteLength) {
buffer = new ArrayBuffer(chunk.byteLength);
Expand All @@ -146,8 +188,9 @@ export function startAudioCapture({
sampleRate: settings.sampleRate ?? 0,
numberOfChannels: settings.channelCount ?? 0,
release() {
// TODO: Don't assert
framePool.push(buffer!);
if (buffer) {
framePool.push(buffer);
}
},
});
},
Expand Down

0 comments on commit 7b6c7be

Please sign in to comment.