[{"data":1,"prerenderedAt":356},["ShallowReactive",2],{"content-en-\u002Fsdk\u002Farchitecture":3},{"id":4,"title":5,"author":6,"body":7,"date":6,"description":348,"extension":349,"meta":350,"navigation":351,"path":352,"seo":353,"stem":354,"tags":6,"__hash__":355},"content_en\u002Fsdk\u002Farchitecture.md","SDK Architecture",null,{"type":8,"value":9,"toc":327},"minimark",[10,14,19,30,34,39,43,47,50,56,60,63,80,83,87,90,96,100,103,120,124,128,134,138,144,148,152,158,162,168,172,321],[11,12,5],"h1",{"id":13},"sdk-architecture",[15,16,18],"h2",{"id":17},"system-diagram","System Diagram",[20,21,26],"pre",{"className":22,"code":24,"language":25},[23],"language-text","                    ┌─────────────────────────────────────────────────────┐\n                    │              Platform Layer (pwa\u002Fmain.ts)           │\n                    │  PwaPlayer: wires all packages together            │\n                    │  Wake Lock, Screenshot, SW registration            │\n                    └──────────────────────┬──────────────────────────────┘\n                                           │\n    ┌──────────────────────────────────────┼──────────────────────────────────┐\n    │                                      │                                  │\n┌───┴────────────┐  ┌─────────┴─────────┐  ┌──┴──────────────┐  ┌───────────────┐\n│  PlayerCore    │  │  RendererLite     │  │  Service Worker  │  │  XmrWrapper   │\n│  Orchestration │  │  XLF rendering   │  │  Chunk streaming │  │  WebSocket     │\n│  Collection    │  │  Element reuse   │  │  Range requests  │  │  13 commands   │\n│  Offline cache │  │  Transitions     │  │  IC interception │  │  Reconnect     │\n│  Commands      │  │  Touch\u002Fkeyboard  │  │  Cache-first     │  │               │\n└───────┬────────┘  └──────────────────┘  └───────────────────┘  └───────────────┘\n        │\n        ├───────────────────────┬───────────────────────┬──────────────────┐\n        │                       │                       │                  │\n┌───────┴──────────┐  ┌────────┴────────┐  ┌──────────┴──────┐  ┌────────┴───────┐\n│  XmdsClient      │  │ ScheduleManager │  │  CacheManager   │  │ StatsCollector  │\n│  + RestClient    │  │ + Interrupts    │  │  + CacheProxy   │  │ + LogReporter   │\n│  SOAP + REST     │  │ + Overlays      │  │  + DlManager    │  │ Proof-of-play   │\n│  ETag caching    │  │ Dayparting      │  │  Parallel chunks│  │ Fault reporting  │\n└──────────────────┘  └─────────────────┘  └─────────────────┘  └────────┬────────┘\n                                                                         │\n                                                                ┌────────┴────────┐\n                                                                │  SyncManager    │\n                                                                │  Lead\u002Ffollower  │\n                                                                │  BC + WebSocket │\n                                                                │  Group isolation│\n                                                                │  Stats delegate │\n                                                                └─────────────────┘\n","text",[27,28,24],"code",{"__ignoreMap":29},"",[15,31,33],{"id":32},"key-design-patterns","Key Design Patterns",[35,36,38],"h3",{"id":37},"_1-platform-independent-core","1. Platform-Independent Core",[40,41,42],"p",{},"PlayerCore contains all business logic without platform assumptions. The platform layer (PWA, Electron, Android) wires packages together and provides platform-specific implementations (Wake Lock, screenshot capture, Service Worker registration).",[35,44,46],{"id":45},"_2-eventemitter-communication","2. EventEmitter Communication",[40,48,49],{},"All modules communicate via events, not direct method calls:",[20,51,54],{"className":52,"code":53,"language":25},[23],"PlayerCore emits:     schedule-updated, collection-complete, purge-request\nRendererLite emits:   layoutStart, layoutEnd, widgetStart, widgetEnd\nStatsCollector:       listens to layout\u002Fwidget events for proof-of-play\nLogReporter:          listens for errors from IC, renderer, collection\n",[27,55,53],{"__ignoreMap":29},[35,57,59],{"id":58},"_3-dual-transport","3. Dual Transport",[40,61,62],{},"The XMDS package provides two transport implementations with identical API surfaces:",[64,65,66,74],"ul",{},[67,68,69,73],"li",{},[70,71,72],"strong",{},"XmdsClient"," (SOAP\u002FXML) — traditional protocol, all CMS versions",[67,75,76,79],{},[70,77,78],{},"RestClient"," (REST\u002FJSON) — 30% smaller payloads, ETag 304 caching",[40,81,82],{},"PlayerCore doesn't know which transport is active.",[35,84,86],{"id":85},"_4-element-reuse","4. Element Reuse",[40,88,89],{},"RendererLite pre-creates ALL widget DOM elements at layout load, stores them in a Map, and toggles visibility:",[20,91,94],{"className":92,"code":93,"language":25},[23],"Layout load:    Pre-create all elements → widgetElements.set(widgetId, element)\nWidget switch:  Hide current → Show next (visibility toggle, no DOM create\u002Fdestroy)\nLayout replay:  Detect isSameLayout → Reuse elements → Restart videos\nLayout change:  Revoke blob URLs → Destroy elements → Create new set\n",[27,95,93],{"__ignoreMap":29},[35,97,99],{"id":98},"_5-service-worker-as-media-server","5. Service Worker as Media Server",[40,101,102],{},"Instead of a local HTTP server, the PWA uses its Service Worker to intercept fetch requests and serve cached media:",[64,104,105,108,111,114,117],{},[67,106,107],{},"Chunk streaming with Range request support",[67,109,110],{},"IC interception (Interactive Control routes)",[67,112,113],{},"Font CSS URL rewriting",[67,115,116],{},"Cache-first with network fallback",[67,118,119],{},"Offline operation",[15,121,123],{"id":122},"data-flow","Data Flow",[35,125,127],{"id":126},"collection-cycle","Collection Cycle",[20,129,132],{"className":130,"code":131,"language":25},[23],"1. RegisterDisplay()      → CMS settings, commands, XMR address\n2. CRC32 comparison       → Skip if unchanged\n3. RequiredFiles()        → File list with MD5 hashes\n4. Download missing files → 4 parallel chunks, MD5 verify\n5. Schedule()             → Layout schedule XML\n6. Parse schedule         → Layouts, overlays, actions, commands\n7. MediaInventory()       → Report cached file inventory\n8. NotifyStatus()         → Report status (disk, timezone, layout)\n9. SubmitStats()          → Proof-of-play records\n10. SubmitLog()           → Queued log entries\n11. SubmitScreenShot()    → If captured\n",[27,133,131],{"__ignoreMap":29},[35,135,137],{"id":136},"offline-mode","Offline Mode",[20,139,142],{"className":140,"code":141,"language":25},[23],"Network down:\n  → XMDS calls fail → Use IndexedDB-cached schedule\u002Fsettings\n  → Media requests → Service Worker serves from Cache API\n  → Stats\u002Flogs → Queued in IndexedDB, submitted when network returns\n  → Player continues rendering with last known schedule\n",[27,143,141],{"__ignoreMap":29},[15,145,147],{"id":146},"storage-architecture","Storage Architecture",[35,149,151],{"id":150},"cache-api-binary-files","Cache API (Binary Files)",[20,153,156],{"className":154,"code":155,"language":25},[23],"Cache: xibo-media\n├── \u002Fmedia\u002F{id}           → Images, videos, audio\n├── \u002Fwidget\u002F{widgetId}    → Widget HTML (getWidgetHtml)\n├── \u002Ffont\u002F{fontFile}      → Font files\n└── \u002Fstatic\u002F{path}        → Static player assets\n",[27,157,155],{"__ignoreMap":29},[35,159,161],{"id":160},"indexeddb-structured-data","IndexedDB (Structured Data)",[20,163,166],{"className":164,"code":165,"language":25},[23],"Database: xibo-player\n├── files         → File metadata (id, type, md5, size)\n├── stats         → Proof-of-play (pending submission)\n├── logs          → Log entries (pending submission)\n├── schedule      → Last known schedule (offline fallback)\n├── settings      → Last known CMS settings\n└── requiredFiles → Last known required files\n",[27,167,165],{"__ignoreMap":29},[15,169,171],{"id":170},"technology-stack","Technology Stack",[173,174,175,191],"table",{},[176,177,178],"thead",{},[179,180,181,185,188],"tr",{},[182,183,184],"th",{},"Layer",[182,186,187],{},"Technology",[182,189,190],{},"Rationale",[192,193,194,206,220,233,244,255,266,277,288,299,310],"tbody",{},[179,195,196,200,203],{},[197,198,199],"td",{},"Language",[197,201,202],{},"JavaScript (ES2020+)",[197,204,205],{},"Cross-platform, no transpilation",[179,207,208,211,217],{},[197,209,210],{},"HTTP client",[197,212,213,216],{},[27,214,215],{},"fetch()"," + fetchWithRetry",[197,218,219],{},"Built-in, configurable retry",[179,221,222,225,230],{},[197,223,224],{},"XML parsing",[197,226,227],{},[27,228,229],{},"DOMParser",[197,231,232],{},"Built-in, namespace-aware",[179,234,235,238,241],{},[197,236,237],{},"Storage",[197,239,240],{},"Cache API + IndexedDB",[197,242,243],{},"Built-in PWA APIs",[179,245,246,249,252],{},[197,247,248],{},"Offline",[197,250,251],{},"Service Worker",[197,253,254],{},"Intercepts all fetches",[179,256,257,260,263],{},[197,258,259],{},"MD5 hashing",[197,261,262],{},"spark-md5",[197,264,265],{},"4KB, ArrayBuffer support",[179,267,268,271,274],{},[197,269,270],{},"PDF",[197,272,273],{},"PDF.js (lazy-loaded)",[197,275,276],{},"Industry standard",[179,278,279,282,285],{},[197,280,281],{},"HLS",[197,283,284],{},"hls.js (lazy-loaded)",[197,286,287],{},"Polyfill for non-Safari",[179,289,290,293,296],{},[197,291,292],{},"Animations",[197,294,295],{},"Web Animations API",[197,297,298],{},"Built-in, GPU-accelerated",[179,300,301,304,307],{},[197,302,303],{},"Build",[197,305,306],{},"Vite",[197,308,309],{},"Tree-shaking, minification",[179,311,312,315,318],{},[197,313,314],{},"Packages",[197,316,317],{},"pnpm workspaces",[197,319,320],{},"Workspace management",[40,322,323,326],{},[70,324,325],{},"Runtime dependencies:"," spark-md5 (4KB), hls.js (lazy), PDF.js (lazy), xibo-communication-framework",{"title":29,"searchDepth":328,"depth":328,"links":329},3,[330,332,339,343,347],{"id":17,"depth":331,"text":18},2,{"id":32,"depth":331,"text":33,"children":333},[334,335,336,337,338],{"id":37,"depth":328,"text":38},{"id":45,"depth":328,"text":46},{"id":58,"depth":328,"text":59},{"id":85,"depth":328,"text":86},{"id":98,"depth":328,"text":99},{"id":122,"depth":331,"text":123,"children":340},[341,342],{"id":126,"depth":328,"text":127},{"id":136,"depth":328,"text":137},{"id":146,"depth":331,"text":147,"children":344},[345,346],{"id":150,"depth":328,"text":151},{"id":160,"depth":328,"text":161},{"id":170,"depth":331,"text":171},"Technical architecture of the XiboPlayer SDK — system diagram, design patterns, and data flow.","md",{},true,"\u002Fsdk\u002Farchitecture",{"title":5,"description":348},"sdk\u002Farchitecture","Wgn4dpe8TknJG4VKvdRwfw2WvC16vPZ34yo-eekCbDg",1775148105253]