diff --git a/system/public/aesthetic.computer/bios.mjs b/system/public/aesthetic.computer/bios.mjs index a42fdbeec7..8251eaec54 100644 --- a/system/public/aesthetic.computer/bios.mjs +++ b/system/public/aesthetic.computer/bios.mjs @@ -4355,12 +4355,7 @@ async function boot(parsed, bpm = 60, resolution, debug) { }); } - // macOS/Chromium can take more than a second to answer this host permission - // query. It is useful state for microphone pieces, but it must not hold up - // the disk worker or the first rendered frame. - const microphonePermissionPromise = checkMicrophonePermission(); - - // Extract embedded source if available + // Extract embedded source if available let embeddedSource = null; try { const embeddedScript = document.getElementById("embedded-source"); @@ -4417,9 +4412,6 @@ async function boot(parsed, bpm = 60, resolution, debug) { firstMessageSent = true; send(firstMessage); consumeDiskSends(send); - microphonePermissionPromise.then((permission) => { - send({ type: "microphone-permission", content: permission }); - }); }; const TAPE_PREVIEW_MAX_FRAMES = 90; @@ -15052,10 +15044,16 @@ async function boot(parsed, bpm = 60, resolution, debug) { return; } - if (type === "microphone") { - receivedMicrophone(content); - return; - } + if (type === "microphone") { + receivedMicrophone(content); + return; + } + + if (type === "microphone-permission-request") { + const permission = await checkMicrophonePermission(); + send({ type: "microphone-permission", content: permission }); + return; + } if (type === "notifications:web") { window.acRequestNotifications?.(content); diff --git a/system/public/aesthetic.computer/lib/disk.mjs b/system/public/aesthetic.computer/lib/disk.mjs index f2ed27815a..948efbf20a 100644 --- a/system/public/aesthetic.computer/lib/disk.mjs +++ b/system/public/aesthetic.computer/lib/disk.mjs @@ -7497,8 +7497,17 @@ class Microphone { recording = false; recordingPromise; permission = ""; + permissionPending = false; + permissionChecked = false; recordingBuffer = null; // Live recording buffer for preview + requestPermission() { + if (this.permissionPending || this.permissionChecked) return this; + this.permissionPending = true; + send({ type: "microphone-permission-request" }); + return this; + } + // Note: can send `{monitor: true}` in `options` for audio feedback. connect(options) { send({ type: "microphone", content: options }); @@ -10644,6 +10653,8 @@ async function makeFrame({ data: { type, content } }) { if (type === "microphone-permission") { microphone.permission = content; + microphone.permissionPending = false; + microphone.permissionChecked = true; if ( content === "granted" && globalKidLispInstance?.containsMicrophoneFunctions?.( diff --git a/system/public/aesthetic.computer/lib/kidlisp.mjs b/system/public/aesthetic.computer/lib/kidlisp.mjs index 7cdfbac27e..e2a039905a 100644 --- a/system/public/aesthetic.computer/lib/kidlisp.mjs +++ b/system/public/aesthetic.computer/lib/kidlisp.mjs @@ -4699,9 +4699,9 @@ class KidLisp { } else if (this.microphoneApi.permission !== "granted") { // Log request for permission (one-time) if (!this.micPermissionRequested) { + this.microphoneApi.requestPermission?.(); console.log("🎤 Microphone permission needed for 'mic' global - please grant access"); this.micPermissionRequested = true; - // Future: Could trigger UI prompt here } } }