Untitled

Anonymous
plain_text
01/27/2026 6:16 PM
4.6 KB
10
Indexable
1. Universal permission logger (works everywhere)

This checks actual capability, not just API support.

export async function logPermissions() {
  const results: Record<string, any> = {};

  // ---------- MICROPHONE ----------
  try {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    results.microphone = "granted";
    stream.getTracks().forEach(t => t.stop());
  } catch (e: any) {
    results.microphone = {
      state: "blocked_or_denied",
      name: e.name,
      message: e.message,
    };
  }

  // ---------- CAMERA ----------
  try {
    const stream = await navigator.mediaDevices.getUserMedia({ video: true });
    results.camera = "granted";
    stream.getTracks().forEach(t => t.stop());
  } catch (e: any) {
    results.camera = {
      state: "blocked_or_denied",
      name: e.name,
      message: e.message,
    };
  }

  // ---------- SPEAKERS / AUDIO PLAYBACK ----------
  try {
    const audio = new Audio();
    await audio.play();
    results.audioPlayback = "granted";
  } catch {
    results.audioPlayback = "blocked_until_user_gesture";
  }

  // ---------- DEVICE ENUMERATION ----------
  try {
    const devices = await navigator.mediaDevices.enumerateDevices();
    results.devices = devices.map(d => ({
      kind: d.kind,
      labelAvailable: Boolean(d.label), // labels only appear after permission
    }));
  } catch (e: any) {
    results.devices = {
      state: "blocked",
      name: e.name,
    };
  }

  console.group("🔐 Permission diagnostics");
  console.table(results);
  console.groupEnd();

  return results;
}

2. Permissions API (works on Chrome / Edge / Android, LIMITED on iOS)

Safari (especially iOS) does not fully implement navigator.permissions, but you can safely attempt it:

export async function logPermissionsAPI() {
  if (!("permissions" in navigator)) {
    console.warn("Permissions API not supported");
    return;
  }

  const permissions: PermissionName[] = [
    "microphone",
    "camera",
    "geolocation",
    "notifications",
  ];

  console.group("🧭 Permissions API states");

  for (const name of permissions) {
    try {
      const status = await navigator.permissions.query({ name });
      console.log(name, status.state); // granted | denied | prompt
    } catch {
      console.log(name, "unsupported");
    }
  }

  console.groupEnd();

  Detect iOS Safari–specific mic blocks (very important for UneeQ)

iOS Safari has hidden failure modes:

export function isIOSSafari() {
  return (
    /iP(hone|ad|od)/.test(navigator.userAgent) &&
    /Safari/.test(navigator.userAgent) &&
    !/Chrome|CriOS|FxiOS/.test(navigator.userAgent)
  );
}


Then log contextual info:

console.log({
  isIOSSafari: isIOSSafari(),
  secureContext: window.isSecureContext,
  hasMediaDevices: !!navigator.mediaDevices,
  hasGetUserMedia: !!navigator.mediaDevices?.getUserMedia,
});


❌ If secureContext === false → mic will never work
❌ If mic requested outside a tap handler → silent failure on iOS

3. Best debug button (recommended)

Add this temporarily to your app:

<button
  onClick={async () => {
    await logPermissions();
    await logPermissionsAPI();
  }}
>
  Debug Permissions
</button>


Tap it once on iPhone Safari → check console via Mac Safari Web Inspector.

  4. Permissions-Policy: 
  
microphone=(self), camera=(self), autoplay=(self)
Referrer-Policy: strict-origin-when-cross-origin

  

Editor is loading...
Leave a Comment