{"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/677329427f32468c74b17f3ec47eeca4e05bec65/packages/stage-shared/src/beat-sync/detector.ts#L120-L156","documentation":"In the Web branch of the beat-sync detector (packages/stage-shared/src/beat-sync/detector.ts:138), audio is captured via navigator.mediaDevices.getDisplayMedia with echoCancellation/noiseSuppression/autoGainControl disabled. If the returned MediaStream has zero audio tracks, this error is thrown: the user shared a surface but no audio came with it, so there is nothing for the analyser to read.","triggerScenarios":"User selects a window in the Chrome screen picker (window capture never carries audio), the 'Share tab audio/system audio' checkbox is left unchecked, or a browser/Firefox configuration where display capture exposes no audio track.","commonSituations":"Music-visualization features that beat-sync from Spotify/YouTube in another tab while the user skips the audio checkbox; kiosk setups; browsers without system-audio capture.","solutions":["Re-run getDisplayMedia and instruct the user to pick a Screen/Tab surface AND tick the share-audio checkbox","Catch this error and fall back to microphone input via getUserMedia({ audio: true })","Pre-check browser support and surface an explicit 'enable audio sharing' hint in the UI"],"exampleFix":"// before\nconst stream = await navigator.mediaDevices.getDisplayMedia({ audio: { echoCancellation: false }, video: true })\nif (stream.getAudioTracks().length === 0) throw new Error('No audio track available in the stream')\n// after\nlet stream = await navigator.mediaDevices.getDisplayMedia({ audio: { echoCancellation: false }, video: true })\nif (stream.getAudioTracks().length === 0) {\n  stream = await navigator.mediaDevices.getUserMedia({ audio: true }) // mic fallback\n}","handlingStrategy":"fallback","validationCode":"const stream = await navigator.mediaDevices.getDisplayMedia({ audio: { echoCancellation: false, noiseSuppression: false, autoGainControl: false }, video: true })\nif (stream.getAudioTracks().length === 0) {\n  // prompt user to retry with audio, or fall back before the detector throws\n  stream.getTracks().forEach(t => t.stop())\n  stream = await navigator.mediaDevices.getUserMedia({ audio: true })\n}","typeGuard":"const hasAudioTrack = (stream: MediaStream): boolean => stream.getAudioTracks().length > 0","tryCatchPattern":"try {\n  await startBeatSync({ env: StageEnvironment.Web })\n}\ncatch (error) {\n  if (error instanceof Error && error.message === 'No audio track available in the stream') {\n    showHint('Tick the share-audio checkbox when picking a screen or tab.')\n    return\n  }\n  throw error\n}","preventionTips":["Tell users to pick Screen/Tab AND enable audio sharing in the picker","Check getAudioTracks().length immediately after getDisplayMedia","Offer microphone input as a documented fallback source"],"tags":["media-capture","getdisplaymedia","audio","browser","beat-sync"],"backgroundTag":"display-capture-without-audio-track","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}