0

Handling late microphone permission in a browser video recorder

A microphone prompt introduces a race into an otherwise simple video recorder. The user starts recording, the browser asks for permission, and the user leaves the page or stops the session before answering. If the permission promise resolves later, its result still needs cleanup.

This note uses the recording implementation in Live Face Swap as a concrete example. The application records an existing result video stream and can add microphone audio. The useful boundary is deciding which resources belong to the recording attempt.

Keep permission failure separate from video failure

The recorder can request microphone access before constructing its recording stream. If access is denied or no microphone is available, it can report that audio is missing and continue with the video tracks. The UI should preserve that distinction so a silent clip does not look like a failed recording.

A permission prompt is still pending work. During that wait, the video source may end or the recording controller may be disposed. Checking only before the request leaves a gap.

Check whether the attempt is still current after awaiting permission

Give each start attempt a monotonically increasing number. Cancellation or disposal increments that number. After the microphone request resolves, compare the captured number with the current one before constructing a recorder. If the attempt is stale, stop the microphone tracks that just arrived and return.

let attempt = 0

async function requestAudioForAttempt() {
  const id = ++attempt
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true })

  if (id !== attempt) {
    stream.getTracks().forEach(track => track.stop())
    return null
  }

  return stream
}

function cancelPendingAttempt() {
  attempt += 1
}

This small example illustrates stale-result cleanup. A complete recorder also handles a rejected permission promise, verifies that the video tracks are still live, and owns cleanup after normal stop or an error. Invalidating the attempt does not dismiss the browser permission prompt. It ensures a late result is released.

Track the resources you own

In the application, the recording stream contains clones of the result video tracks and any acquired microphone tracks. Cleanup can then stop those owned tracks while the source video has its own lifecycle. Keep the permission result in a local variable until ownership has transferred successfully, so initialization errors can release it too.

Test the race deliberately

Use a deferred microphone promise in a regression test. Start the recording attempt, cancel it, then resolve the promise with fake audio tracks. Assert that the late tracks are stopped and no recorder starts. Separately test denial with a live video source and confirm that a silent clip can still be produced.

The project already has tests for both cases. Its 10 existing recording tests passed during this review using mocked media dependencies. Real browser permission UX and encoding remain separate integration checks.

References

I build Live Face Swap. This article was prepared with AI assistance and checked against the recording implementation and its regression tests.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí