{"record":{"id":"e86c3576ca8abc8e","repo":"iflytek/astron-agent","slug":"code-dynamic-from-e-name-e-message-logged-as","errorCode":null,"errorMessage":"code (dynamic; from e.name||e.message, logged as '请求录音权限错误')","messagePattern":"code \\(dynamic; from e\\.name\\|\\|e\\.message, logged as '请求录音权限错误'\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"console/frontend/src/utils/record/recorder-core.js","lineNumber":875,"sourceCode":"          Recorder.Stream = stream;\n          if (lockFail()) return;\n\n          if (Recorder.IsOpen()) {\n            if (oldStream) This.CLog('发现同时多次调用open', 1);\n\n            Connect(streamStore, 1);\n            ok();\n          } else {\n            failCall('录音功能无效：无音频流');\n          }\n        }, 100);\n      };\n      var f2 = function (e) {\n        var code = e.name || e.message || e.code + ':' + e;\n        This.CLog('请求录音权限错误', 1, e);\n\n        codeFail(code, '无法录音：' + code);\n        throw new Error(code);\n      };\n\n      var trackSet = {\n        noiseSuppression: false, //默认禁用降噪，原声录制，免得移动端表现怪异（包括系统播放声音变小）\n        echoCancellation: false, //回声消除\n      };\n      var trackSet2 = This.set.audioTrackSet;\n      for (var k in trackSet2) trackSet[k] = trackSet2[k];\n      trackSet.sampleRate = Recorder.Ctx.sampleRate; //必须指明采样率，不然手机上MediaRecorder采样率16k\n\n      try {\n        var pro = Recorder.Scope[getUserMediaTxt]({ audio: trackSet }, f1, f2);\n      } catch (e) {\n        //不能设置trackSet就算了\n        This.CLog(getUserMediaTxt, 3, e);\n        pro = Recorder.Scope[getUserMediaTxt]({ audio: true }, f1, f2);\n      }\n      if (pro && pro.then) {","sourceCodeStart":857,"sourceCodeEnd":893,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/frontend/src/utils/record/recorder-core.js#L857-L893","documentation":"In recorder-core's getUserMedia permission request path (f2), any exception from navigator.mediaDevices.getUserMedia is converted to code = e.name || e.message || e.code+':'+e, logged as '请求录音权限错误', passed to codeFail ('无法录音：'+code), and thrown as new Error(code). Typical codes are NotAllowedError, NotFoundError, NotReadableError.","triggerScenarios":"getUserMedia rejecting: user denied permission (NotAllowedError/SecurityError), no audio input device (NotFoundError), device busy (NotReadableError), or insecure context making mediaDevices undefined.","commonSituations":"Browser privacy settings blocking mic; external USB mic unplugged mid-session; kiosk browsers without media permissions policy; iframe missing allow=\"microphone\".","solutions":["Map e.name to a user-facing message: NotAllowedError → enable permission, NotFoundError → connect a mic, NotReadableError → close apps using the mic","Add allow=\"microphone\" to iframes embedding the console","Ensure HTTPS origin; getUserMedia is unavailable on insecure pages","Catch the thrown code and offer a retry (requestPermission again) instead of crashing"],"exampleFix":"// before\nrec.open(success, fail); // fail receives '无法录音：NotAllowedError'\n// after\ntry {\n  rec.open(success, (msg) => showMicError(msg));\n} catch (code) {\n  if (code === 'NotAllowedError') promptPermissionFix();\n  else if (code === 'NotFoundError') promptConnectMic();\n}","handlingStrategy":"try-catch","validationCode":"if (!window.isSecureContext || !navigator.mediaDevices) {\n  message.error('无法录音：需要 HTTPS 且支持 getUserMedia');\n  return;\n}","typeGuard":"function hasMicAccess() { return !!navigator.mediaDevices?.enumerateDevices; }","tryCatchPattern":"try {\n  rec.open(onOk, onFail);\n} catch (code) {\n  switch (code) {\n    case 'NotAllowedError': showPermissionFix(); break;\n    case 'NotFoundError': showNoMic(); break;\n    case 'NotReadableError': showMicBusy(); break;\n    default: console.error('请求录音权限错误:', code);\n  }\n}","preventionTips":["Add allow=\"microphone\" to iframes","Map DOMException names to actionable user messages","Offer a permission-reset guide (site settings) in the UI"],"tags":["audio","microphone","permissions","getusermedia"],"backgroundTag":"permission-denied","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}