抓包到源碼級(jí)事件處理)
音視頻后端物聯(lián)網(wǎng)計(jì)算機(jī)視覺【免費(fèi)下載鏈接】scryptedScrypted is a high performance video integration and automation platform項(xiàng)目地址https://gitcode.com/gh_mirrors/sc/scrypted點(diǎn)擊查看免費(fèi)下載本文以 Scrypted 倉庫中 Amcrest 插件的 AD410 門鈴真實(shí)事件抓包plugins/amcrest/ad410.md為核心素材逐事件解讀 Amcrest 門鈴在按鍵呼叫過程中推送的 multipart 事件流并結(jié)合插件源碼amcrest-api.ts、main.ts說明這些事件如何被解析、匹配最終驅(qū)動(dòng) Scrypted 的BinarySensor門鈴狀態(tài)與MotionSensor移動(dòng)偵測(cè)接口幫助你在調(diào)試 Amcrest 門鈴、對(duì)接自定義事件或排查門鈴不觸發(fā)問題時(shí)具備完整的協(xié)議級(jí)認(rèn)知。AD410 門鈴的真實(shí)事件流抓包plugins/amcrest/ad410.md 記錄了 Amcrest AD410 門鈴在一次完整按鍵呼叫訪客按下門鈴按鈕、無人接聽、隨后掛斷過程中通過 HTTP 長(zhǎng)連接推送的原始事件流。這是理解整個(gè) Amcrest 事件協(xié)議最直接的樣本event --myboundary Content-Type: text/plain Content-Length:41 Code_CallRemoveMask;actionStart;index0 event --myboundary Content-Type: text/plain Content-Length:36 CodeAlarmLocal;actionStart;index0 event --myboundary Content-Type: text/plain Content-Length:148 Code_DoTalkAction_;actionPulse;index0;data{ Action : Invite, CallID : 20220406135211095697192.168.10.20, CallSrcMask : 4 } event --myboundary Content-Type: text/plain Content-Length:68 CodeCallNoAnswered;actionStart;index0;data{ CallID : 4 } event --myboundary Content-Type: text/plain Content-Length:41 CodePhoneCallDetect;actionStart;index0 event --myboundary Content-Type: text/plain Content-Length:41 CodeVideoMotionInfo;actionState;index0 event --myboundary Content-Type: text/plain Content-Length:185 Code_DoTalkAction_;actionPulse;index0;data{ Action : Hangup, CallID : 20220406135211095697192.168.10.20, CallSrcMask : 4, HangupReason : HangupByPhone } event --myboundary Content-Type: text/plain Content-Length:35 CodeAlarmLocal;actionStop;index0 event --myboundary Content-Type: text/plain Content-Length:39 CodeCallNoAnswered;actionStop;index0 event --myboundary Content-Type: text/plain Content-Length:95 CodeVideoMotion;actionStop;index0;data{ Id : [ 0 ], RegionName : [ Region1 ] } event --myboundary Content-Type: text/plain Content-Length:40 CodePhoneCallDetect;actionStop;index0 event --myboundary Content-Type: text/plain Content-Length:40 Code_CallRemoveMask;actionStop;index0分幀格式multipart 邊界 頭 定長(zhǎng) body抓包中每一幀part的構(gòu)成非常清晰--myboundarymultipart 流的邊界行用于分隔相鄰兩個(gè)事件 part。抓包中邊界行前的event前綴是捕獲工具/控制臺(tái)打印的日志前綴不屬于流內(nèi)容本身Content-Type: text/plain該 part 的 MIME 類型聲明 body 是純文本Content-Length:N該 part body 的精確字節(jié)數(shù)例如Code_CallRemoveMask;actionStart;index0恰好是 41 字節(jié)空行頭與 body 的分隔bodyCode...;action...;index...;data{...}形式的事件負(fù)載其中data字段是可選的 JSON。這個(gè)分幀方式與 amcrest-api.ts 中的解析邏輯一一對(duì)應(yīng)插件從 HTTP 響應(yīng)的content-type頭中解析出 boundary源碼注釋明確指出 Amcrest 可能發(fā)送--myboundary或帶空格的-- myboundary兩種形式再對(duì)每個(gè) part 讀取頭行、按Content-Length讀取定長(zhǎng) body。逐事件解讀一次完整門鈴呼叫的生命周期把 12 個(gè)事件按時(shí)間序展開就是一次 AD410 門鈴呼叫的完整狀態(tài)機(jī)順序事件語義1Code_CallRemoveMask;actionStart;index0呼叫開始解除掩碼門鈴內(nèi)部狀態(tài)插件忽略2CodeAlarmLocal;actionStart;index0本地報(bào)警/響鈴開始插件忽略3Code_DoTalkAction_;actionPulse;index0;data{Action:Invite,...}訪客按下門鈴按鈕發(fā)起雙向?qū)χv邀請(qǐng)關(guān)鍵事件4CodeCallNoAnswered;actionStart;index0;data{CallID:4}呼叫開始被標(biāo)記為未應(yīng)答5CodePhoneCallDetect;actionStart;index0檢測(cè)到電話呼叫門鈴被按6CodeVideoMotionInfo;actionState;index0移動(dòng)偵測(cè)狀態(tài)脈沖訪客靠近鏡頭觸發(fā)7Code_DoTalkAction_;actionPulse;index0;data{Action:Hangup,...,HangupReason:HangupByPhone}對(duì)講結(jié)束由電話側(cè)掛斷關(guān)鍵事件8CodeAlarmLocal;actionStop;index0本地報(bào)警停止9CodeCallNoAnswered;actionStop;index0未應(yīng)答狀態(tài)結(jié)束10CodeVideoMotion;actionStop;index0;data{Id:[0],RegionName:[Region1]}移動(dòng)偵測(cè)區(qū)域停止RegionName指出觸發(fā)區(qū)域11CodePhoneCallDetect;actionStop;index0電話呼叫檢測(cè)結(jié)束12Code_CallRemoveMask;actionStop;index0呼叫結(jié)束掩碼恢復(fù)幾個(gè)值得注意的細(xì)節(jié)CallID的構(gòu)成20220406135211095697192.168.10.20遵循時(shí)間戳序號(hào)來源IP的格式Invite 與 Hangup 兩個(gè)脈沖攜帶相同CallID可用于配對(duì)一次完整呼叫CallSrcMask: 4表示呼叫來源掩碼。動(dòng)作語義action取值為Start進(jìn)入某狀態(tài)、Stop離開某狀態(tài)、Pulse瞬時(shí)脈沖常帶 JSONdata、State狀態(tài)上報(bào)。index0通道索引0 基。插件會(huì)把index 1與設(shè)備配置的通道號(hào)比較不匹配則丟棄見后文。對(duì)照AD110 的門鈴事件流倉庫中另有 AD110 抓包 可以對(duì)照閱讀。AD110 的呼叫事件序列更精簡(jiǎn)NTPAdjustTime;actionPulseNTP 校時(shí)脈沖、_DoTalkAction_;actionPulseInvite、CallNoAnswered;actionStart、CallNoAnswered;actionStop、_DoTalkAction_;actionPulseHangup。兩者的對(duì)比揭示了 Amcrest 不同型號(hào)門鈴的事件協(xié)議差異AD410 會(huì)額外推送PhoneCallDetect、AlarmLocal、_CallRemoveMask、VideoMotion/VideoMotionInfo等事件形成完整的呼叫 移動(dòng)偵測(cè)生命周期AD110 的抓包中則沒有這些條目或其固件版本未推送AD110 抓包中還混入了[HomeKit]: snapshot requested for reason: 1日志行——這是 Scrypted 控制臺(tái)輸出與原始事件流同一捕獲通道產(chǎn)生的混排結(jié)果并非 multipart 事件流的一部分閱讀此類抓包時(shí)需要區(qū)分關(guān)鍵的雙向?qū)χv事件_DoTalkAction_的 Invite/Hangup 脈沖、CallNoAnswered在兩個(gè)型號(hào)上完全一致這正是插件能夠用統(tǒng)一邏輯處理多種門鈴的基礎(chǔ)。源碼級(jí)解析listenEvents 如何消費(fèi)事件流訂閱端點(diǎn)與邊界解析AmcrestCameraClient.listenEvents() 是整個(gè)事件鏈的入口它向設(shè)備發(fā)起一個(gè) HTTP 長(zhǎng)連接請(qǐng)求http://ip/cgi-bin/eventManager.cgi?actionattachcodes[All]codes[All]表示訂閱設(shè)備的全部事件碼。拿到可讀流后解析流程與上面抓包的分幀格式嚴(yán)格對(duì)應(yīng)逐行讀取邊界common/src/read-stream.ts 的readUntil/readLine按換行切分遇到終止邊界--myboundary--跳過讀頭readAmcrestMessage 持續(xù)讀取行直到空行。源碼注釋專門處理了一個(gè) DahuaAmcrest 同源固件的畸形情況——header 與 body 之間缺少換行分隔Content-Length:39后緊跟 body 行此時(shí)把不含:的行unshift回流中返回避免誤判讀 bodycommon/src/rtsp-server.ts 的readBody按解析出的Content-Length精確讀取定長(zhǎng)數(shù)據(jù)這保證了data{...}中跨多行的 JSON如抓包里 Invite 脈沖的 148 字節(jié)能被完整取出容錯(cuò)兼容解析循環(huán)還處理了 Dahua 設(shè)備偶發(fā)在流中插入完整HTTP/1.1 200 OK響應(yīng)消息的 bugamcrest-api.ts#L271-L281將其整段跳過并記錄日志。事件碼表AmcrestEvent 枚舉與匹配AmcrestEvent 枚舉 定義了插件關(guān)心的全部事件碼匹配方式是子串包含data.indexOf(event) ! -1。對(duì)照 AD410 抓包可以精確看出哪些事件被消費(fèi)、哪些被靜默忽略export enum AmcrestEvent { MotionStart CodeVideoMotion;actionStart, MotionStop CodeVideoMotion;actionStop, MotionInfo CodeVideoMotionInfo;actionState, AudioStart CodeAudioMutation;actionStart, AudioStop CodeAudioMutation;actionStop, TalkInvite Code_DoTalkAction_;actionInvite, TalkHangup Code_DoTalkAction_;actionHangup, TalkPulse Code_DoTalkAction_;actionPulse, AlarmIPCStart CodeAlarmIPC;actionStart, AlarmIPCStop CodeAlarmIPC;actionStop, PhoneCallDetectStart CodePhoneCallDetect;actionStart, PhoneCallDetectStop CodePhoneCallDetect;actionStop, DahuaTalkInvite CodeCallNoAnswered;actionStart, DahuaTalkHangup CodePassiveHungup;actionStart, DahuaCallDeny CodeHungupPhone;actionPulse, DahuaTalkPulse Code_CallNoAnswer_;actionPulse, FaceDetection CodeFaceDetection;actionStart, SmartMotionHuman CodeSmartMotionHuman;actionStart, SmartMotionVehicle CodeVehicle;actionStart, CrossLineDetection CodeCrossLineDetection;actionStart, CrossRegionDetection CodeCrossRegionDetection;actionStart, }以 AD410 抓包為參照被消費(fèi)的PhoneCallDetect;actionStart/Stop、_DoTalkAction_;actionPulseInvite/Hangup 靠 payload 區(qū)分、CallNoAnswered;actionStart、VideoMotionInfo;actionState、VideoMotion;actionStop被忽略的_CallRemoveMask、AlarmLocal、CallNoAnswered;actionStop——它們不在枚舉中解析循環(huán)對(duì)它們不做任何狀態(tài)變更。這意味著事件協(xié)議中相當(dāng)一部分內(nèi)部簿記事件對(duì)上層是透明的。每個(gè)事件 emit 時(shí)還會(huì)攜帶從 body 中解析出的index通道索引與dataJSON 負(fù)載解析器把 body 按;切分提取index與data兩個(gè)片段data會(huì)被JSON.parse成對(duì)象amcrest-api.ts#L297-L319。此外智能檢測(cè)事件SmartMotionHuman、Vehicle、FaceDetection、CrossLine/CrossRegionDetection會(huì)被進(jìn)一步映射為person/car/face類別并額外 emitsmart事件供ObjectDetector接口輸出倉庫中 plugins/amcrest/dumps/amcrest-face-detected.json 與 plugins/amcrest/dumps/amcrest-human-detected.json 保留了這類事件的真實(shí) JSON 樣本包含BoundingBox、ObjectType、Confidence等字段。事件流如何變成 Scrypted 的傳感器狀態(tài)門鈴按鍵 → BinarySensorAmcrestCamera.listenEvents() 訂閱事件流后把事件碼翻譯為設(shè)備狀態(tài)。處理 AD410 門鈴按鍵的關(guān)鍵分支main.ts#L260-L286else if (event AmcrestEvent.TalkInvite || event AmcrestEvent.PhoneCallDetectStart || event AmcrestEvent.AlarmIPCStart || event AmcrestEvent.DahuaTalkInvite) { ... this.binaryState true; } else if (event AmcrestEvent.TalkHangup || event AmcrestEvent.PhoneCallDetectStop || ... ) { this.binaryState false; } else if (event AmcrestEvent.TalkPulse doorbellType AMCREST_DOORBELL_TYPE) { if (payload.includes(Invite)) { this.binaryState true; } else if (payload.includes(Hangup)) { this.binaryState false; } }把 AD410 抓包代入這段邏輯binaryState的翻轉(zhuǎn)軌跡是_DoTalkAction_Invite 脈沖 →binaryState true訪客按下按鈕門鈴響CallNoAnswered;actionStart、PhoneCallDetect;actionStart→ 再次置true冗余確認(rèn)_DoTalkAction_Hangup 脈沖HangupReason: HangupByPhone→binaryState falsePhoneCallDetect;actionStop→ 置false。值得注意的是TalkPulse分支對(duì)payload完整 body 字符串做includes(Invite)/includes(Hangup)判斷——這正是為什么 Invite/Hangup 兩個(gè)脈沖必須攜帶 JSONdata字段如果某固件的脈沖不帶data該分支不會(huì)翻轉(zhuǎn)狀態(tài)只能依賴PhoneCallDetect的 Start/Stop 兜底。而事件負(fù)載中的index會(huì)先經(jīng)過通道過濾main.ts#L231-L236index 1必須等于設(shè)備配置的Channel Number OverridertspChannel設(shè)置項(xiàng)多通道 NVR 場(chǎng)景下避免串通道。接口暴露上updateDevice() 在設(shè)備Doorbell Type設(shè)為Amcrest Doorbell時(shí)把設(shè)備類型置為Doorbell并追加BinarySensor與Intercom接口——這解釋了為什么 README 中門鈴配置的第一步是SelectTypeisDoorbell只有如此門鈴事件才會(huì)被映射到二進(jìn)制傳感器而非僅日志。移動(dòng)偵測(cè)20 秒超時(shí)而非 Stop 事件AD410 抓包中的VideoMotionInfo;actionState事件 6與VideoMotion;actionStop事件 10的處理體現(xiàn)了插件的防抖設(shè)計(jì)main.ts#L211-L253MotionStart/SmartMotionHuman/SmartMotionVehicle/CrossLine/RegionDetection→ 立即motionDetected true并重置一個(gè)20 秒的motionTimeoutMotionInfo即VideoMotionInfo;actionState脈沖→ 若尚未檢測(cè)到則補(bǔ)置true同樣重置 20 秒計(jì)時(shí)MotionStop→有意不立即清除狀態(tài)注釋寫明use resetMotionTimeout即依賴 20 秒無新事件后自動(dòng)回落為false。這種事件置位 超時(shí)回落的模式避免了固件偶發(fā)漏推Start/Stop配對(duì)事件時(shí)傳感器卡死的問題——這也與抓包中VideoMotion;actionStop攜帶RegionName: [Region1]對(duì)應(yīng) Amcrest 配置界面第一號(hào)運(yùn)動(dòng)偵測(cè)區(qū)域相互印證即使 Stop 到達(dá)狀態(tài)清理仍統(tǒng)一由超時(shí)完成。監(jiān)聽器?;頻istenLoop 的重連與空閑超時(shí)事件長(zhǎng)連接的健壯性由基類 RtspSmartCamera.listenLoop() 保證監(jiān)聽器創(chuàng)建失敗、連接close或error時(shí)自動(dòng)銷毀并延時(shí)重建rtsp.ts#L183-L191連接后啟動(dòng) 5 分鐘空閑看門狗期間沒有任何data事件即設(shè)備長(zhǎng)時(shí)間無活動(dòng)則銷毀監(jiān)聽并重建防止半死連接每個(gè)事件到達(dá)都會(huì)刷新空閑計(jì)時(shí)因此在門鈴頻繁觸發(fā)的場(chǎng)景下連接會(huì)持續(xù)?;睢istenEvents內(nèi)部還會(huì)stream.socket.setKeepAlive(true)維持 TCP ?;頰mcrest-api.ts#L250。調(diào)試時(shí)可在設(shè)備設(shè)置中開啟debug每個(gè)原始事件幀會(huì)打印到控制臺(tái)rtsp.ts#L211-L215——ad410.md 與 ad110.md 這兩份文檔本身就是這類調(diào)試輸出的歸檔樣本。實(shí)戰(zhàn)配置與 AD410 已知怪癖門鈴設(shè)備的基本配置按 Amcrest 插件 README 的門鈴配置要求plugins/amcrest/README.mdType選擇Doorbell設(shè)備名稱下方Username為admin設(shè)備初始化時(shí)設(shè)置的本地管理員賬號(hào)不是 Amcrest Smart Home 云賬號(hào)Doorbell Type選擇Amcrest Doorbell對(duì)應(yīng)源碼中的 AMCREST_DOORBELL_TYPE可選值還有Dahua Doorbell若雙向?qū)χv開始時(shí)門鈴重啟/崩潰用 Amcrest Smart Home 應(yīng)用在 Device Information 中關(guān)閉Record Audio選項(xiàng)代價(jià)是 SD 卡不再錄音。雙向?qū)χv的音頻通路當(dāng)事件把binaryState置真后可通過Intercom接口發(fā)起對(duì)講。startIntercom() 對(duì) Amcrest 門鈴非 Dahua的路徑是把媒體轉(zhuǎn)成 FFmpeg 輸入用 FFmpeg 重編碼為AACadts 封裝后以 1024 字節(jié)分塊 POST 到http://ip/cgi-bin/audio.cgi?actionpostAudiohttptypesinglepartchannel通道號(hào)Content-Type為Audio/AACDahua 門鈴則走pcm_alaw/Audio/G.711A編碼。另外 main.ts#L757 的注釋提示ONVIF 雙向音頻在大多數(shù)機(jī)型上表現(xiàn)更好但AD110 例外添加設(shè)備時(shí)插件會(huì)自動(dòng)探測(cè)devAudioOutput.cgi并默認(rèn)選擇ONVIF見 checkTwoWayAudio()。AD410 特有的 caps 怪癖configureCodecs() 中有一段針對(duì) AD410 的特殊處理源碼注釋明確寫道ad410 doesnt return a camera number if accessed directly——當(dāng)直連 AD410不經(jīng)過 NVR查詢編碼能力時(shí)encode.cgi?actiongetConfigCaps返回的鍵不帶通道編號(hào)前綴。解析器因此在caps[0].MainFormat[0]找不到值時(shí)回退到caps.MainFormat[0]。如果你在為 AD410 配置碼率/分辨率時(shí)遇到能力查詢異常這是一個(gè)已知的設(shè)備側(cè)差異而非配置錯(cuò)誤。設(shè)備信息獲取方面插件通過 probe.ts 的magicBox.cgi?actiongetSystemInfo解析deviceType/serialNumber等設(shè)備參數(shù)來校驗(yàn)憑據(jù)與型號(hào)main.ts 的 updateDeviceInfo() 還會(huì)逐一查詢getVendor/getSerialNo/getDeviceType/getSoftwareVersion失敗僅記錄錯(cuò)誤而不阻塞設(shè)備使用。小結(jié)AD410 的一次門鈴呼叫會(huì)產(chǎn)生 12 個(gè) multipart 事件幀核心信號(hào)是_DoTalkAction_的 Invite/Hangup 脈沖與PhoneCallDetect的 Start/Stop其余_CallRemoveMask、AlarmLocal、CallNoAnswered;actionStop為插件忽略的內(nèi)部簿記事件事件流由eventManager.cgi?actionattachcodes[All]長(zhǎng)連接推送分幀為邊界 Content-Type/Content-Length 頭 定長(zhǎng) bodydata字段攜帶跨行 JSON插件通過 AmcrestEvent 枚舉 做子串匹配把事件翻譯成BinarySensor門鈴與MotionSensor20 秒超時(shí)回落狀態(tài)并由 listenLoop 提供重連與空閑看門狗?;钆渲瞄T鈴時(shí)需將設(shè)備Type設(shè)為Doorbell、Doorbell Type設(shè)為Amcrest Doorbell并使用設(shè)備本地admin憑據(jù)調(diào)試原始事件幀可開啟設(shè)備debug設(shè)置ad410.md 與 ad110.md 是兩份可對(duì)照的真實(shí)抓包樣本。贊分享音視頻后端物聯(lián)網(wǎng)計(jì)算機(jī)視覺【免費(fèi)下載鏈接】scryptedScrypted is a high performance video integration and automation platform項(xiàng)目地址https://gitcode.com/gh_mirrors/sc/scrypted點(diǎn)擊查看免費(fèi)下載相關(guān)推薦Scrypted Amcrest 插件實(shí)戰(zhàn)接入 Amcrest 攝像頭、門鈴與 NVR 的完整配置指南Scrypted Amcrest 插件實(shí)戰(zhàn)接入 Amcrest 攝像頭、門鈴與 NVR 的完整配置指南 本篇技術(shù)文章圍繞 Scrypted 倉庫中的 Amcr音視頻后端物聯(lián)網(wǎng)計(jì)算機(jī)視覺go2rtc項(xiàng)目中Amcrest AD410門鈴雙向音頻配置指南go2rtc項(xiàng)目中Amcrest AD410門鈴雙向音頻配置指南 背景介紹 在智能家居監(jiān)控系統(tǒng)中Amcrest AD410門鈴是一款基于Dahua技術(shù)的流行設(shè)音視頻后端Mistral-Nemo-Instruct-2407代碼生成實(shí)戰(zhàn)從基礎(chǔ)編程到復(fù)雜算法實(shí)現(xiàn)終極指南Mistral Nemo Instruct 2407代碼生成實(shí)戰(zhàn)從基礎(chǔ)編程到復(fù)雜算法實(shí)現(xiàn)終極指南 Mistral Nemo Instruct 2407 是一款上一篇解鎖創(chuàng)意工坊WorkshopDL跨平臺(tái)工具全解析下一篇LangChain為什么它是構(gòu)建AI代理的首選框架3個(gè)關(guān)鍵優(yōu)勢(shì)解析創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考