{"record":{"id":"bc590306965a3b2f","repo":"moeru-ai/airi","slug":"no-audio-track-available-in-the-stream","errorCode":null,"errorMessage":"No audio track available in the stream","messagePattern":"No audio track available in the stream","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-shared/src/beat-sync/detector.ts","lineNumber":138,"sourceCode":"\n  const updateParameters = (params: Partial<AnalyserWorkletParameters>) => {\n    analyser?.updateParameters(params)\n  }\n\n  const startScreenCapture = async () => start(async (ctx) => {\n    switch (options.env) {\n      case StageEnvironment.Web: {\n        const stream = await navigator.mediaDevices.getDisplayMedia({\n          audio: {\n            echoCancellation: false,\n            noiseSuppression: false,\n            autoGainControl: false,\n          },\n          video: true,\n        })\n\n        if (stream.getAudioTracks().length === 0) {\n          throw new Error('No audio track available in the stream')\n        }\n\n        stream.getAudioTracks().forEach((track) => {\n          let stopCalled = false\n          track.addEventListener('ended', () => {\n            if (stopCalled)\n              return\n            stopCalled = true\n            stop()\n          })\n        })\n\n        const node = ctx.createMediaStreamSource(stream)\n        stopSource = () => {\n          stream.getTracks().forEach(track => track.stop())\n        }\n\n        return node","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/packages/stage-shared/src/beat-sync/detector.ts#L120-L156","documentation":"Thrown by the beat-sync detector's Web environment path when `navigator.mediaDevices.getDisplayMedia` returns a stream with zero audio tracks. The detector needs the system/audio loopback to perform beat analysis, so an audio-less screen share is rejected immediately after the user grants the display.","triggerScenarios":"The user picks a screen/window/tab in the getDisplayMedia picker but does not (or cannot) share audio — e.g. unchecks 'Share audio', shares a tab that has no audio, or uses a browser/OS combination that does not expose audio capture. The check `stream.getAudioTracks().length === 0` fires right after the share is granted.","commonSituations":"Browser/OS does not support system-audio capture (notably most configurations on macOS Chrome, or Firefox); user deselects 'Share audio' in the picker; sharing a tab or window with no audio output; permission prompts that only grant video.","solutions":["Instruct the user to enable 'Share audio' / 'Share tab audio' in the getDisplayMedia picker.","On macOS Chrome, note system-audio capture is limited; recommend a platform/browser that supports it, or accept that beat-sync may be unavailable.","Catch the error and show a user-facing message explaining audio sharing is required for beat sync.","Optionally re-prompt the user to re-share with audio enabled."],"exampleFix":"// before\nconst stream = await navigator.mediaDevices.getDisplayMedia({ audio: true, video: true })\n// (detector throws if no audio track)\n\n// after\ntry {\n  await startBeatSync()\n} catch (e) {\n  if (e.message === 'No audio track available in the stream') {\n    showUser('Enable \"Share audio\" in the screen-share prompt to use Beat Sync.')\n  } else throw e\n}","handlingStrategy":"try-catch","validationCode":"async function hasAudioTrack(stream: MediaStream): Promise<boolean> {\n  return stream.getAudioTracks().length > 0\n}\n\nconst stream = await navigator.mediaDevices.getDisplayMedia({ audio: true, video: true })\nif (!await hasAudioTrack(stream)) {\n  stream.getTracks().forEach(t => t.stop())\n  throw new Error('Display share had no audio track. Enable \"Share audio\".')\n}","typeGuard":"function streamHasAudio(stream: MediaStream): boolean {\n  return stream.getAudioTracks().length > 0\n}","tryCatchPattern":"try {\n  await startBeatSync()\n} catch (e) {\n  if (e instanceof Error && e.message === 'No audio track available in the stream') {\n    showUser('Enable \"Share audio\" in the screen-share prompt to use Beat Sync.')\n    return\n  }\n  throw e\n}","preventionTips":["Tell users to enable 'Share audio' when the getDisplayMedia picker appears.","On platforms without system-audio capture (e.g. macOS Chrome), warn users beat sync may be unavailable.","Catch the error and present a clear, actionable message rather than a raw stack.","Stop the (video-only) stream tracks when audio is missing to release the permission."],"tags":["beat-sync","web","media-capture","getdisplaymedia","user-action"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}