[{"data":1,"prerenderedAt":1128},["ShallowReactive",2],{"docs-ca-\u002Fdocs\u002Fsdk\u002Ftechnical-manual":3},{"id":4,"title":5,"author":6,"body":7,"date":6,"description":1120,"extension":1121,"meta":1122,"navigation":1123,"path":1124,"seo":1125,"stem":1126,"tags":6,"__hash__":1127},"content_en\u002Fdocs\u002Fsdk\u002Ftechnical-manual.md","Technical Manual",null,{"type":8,"value":9,"toc":1097},"minimark",[10,14,18,23,77,81,86,89,96,152,158,170,174,177,291,294,298,302,305,646,650,754,758,797,801,805,808,816,842,846,896,900,904,910,913,917,931,935,938,942,950,955,979,983,1090,1093],[11,12,5],"h1",{"id":13},"technical-manual",[15,16,17],"p",{},"Complete technical reference for developers and system integrators working with the xiboplayer ecosystem.",[19,20,22],"h2",{"id":21},"sdk-internals","SDK internals",[24,25,26,39],"table",{},[27,28,29],"thead",{},[30,31,32,36],"tr",{},[33,34,35],"th",{},"Topic",[33,37,38],{},"Description",[40,41,42,55,66],"tbody",{},[30,43,44,52],{},[45,46,47],"td",{},[48,49,51],"a",{"href":50},"\u002Fdocs\u002Fsdk\u002Farchitecture","Architecture",[45,53,54],{},"Package dependency graph, data flow, event bus, platform abstraction",[30,56,57,63],{},[45,58,59],{},[48,60,62],{"href":61},"\u002Fdocs\u002Fsdk\u002Fpackages","Package Reference",[45,64,65],{},"All 14 @xiboplayer\u002F* packages with exports and dependencies",[30,67,68,74],{},[45,69,70],{},[48,71,73],{"href":72},"\u002Fdocs\u002Fsdk\u002Fcomparison","Feature Comparison",[45,75,76],{},"Detailed comparison vs upstream Xibo players (Windows, XLR, arexibo)",[19,78,80],{"id":79},"communication-protocols","Communication protocols",[82,83,85],"h3",{"id":84},"xmds-cms-player","XMDS (CMS ↔ Player)",[15,87,88],{},"The player communicates with the CMS via XMDS — available in both SOAP and REST transports:",[15,90,91,95],{},[92,93,94],"strong",{},"Collection cycle"," (every 5-900 seconds):",[97,98,99,107,113,119,122,128,134,140,146],"ol",{},[100,101,102,106],"li",{},[103,104,105],"code",{},"RegisterDisplay()"," — register\u002Fre-register, receive settings and XMR address",[100,108,109,112],{},[103,110,111],{},"RequiredFiles()"," — get file manifest with MD5 hashes (CRC32 skip optimization)",[100,114,115,118],{},[103,116,117],{},"Schedule()"," — get layout schedule XML",[100,120,121],{},"Download missing files — 4 parallel chunks, MD5 verification",[100,123,124,127],{},[103,125,126],{},"MediaInventory()"," — report cached file inventory",[100,129,130,133],{},[103,131,132],{},"NotifyStatus()"," — report device status (disk, timezone, layout)",[100,135,136,139],{},[103,137,138],{},"SubmitStats()"," — proof-of-play records",[100,141,142,145],{},[103,143,144],{},"SubmitLog()"," — queued log entries (batched, max 50)",[100,147,148,151],{},[103,149,150],{},"SubmitScreenShot()"," — captured screenshot (if configured)",[15,153,154,157],{},[92,155,156],{},"REST vs SOAP",":",[159,160,161,164,167],"ul",{},[100,162,163],{},"REST: JSON payloads (~30% smaller), ETag 304 caching, JWT auth",[100,165,166],{},"SOAP: XML, compatible with all CMS versions (v3-v7)",[100,168,169],{},"Auto-detected at startup via protocol probe",[82,171,173],{"id":172},"xmr-cms-player-push","XMR (CMS → Player push)",[15,175,176],{},"Real-time WebSocket commands from CMS to player:",[24,178,179,189],{},[27,180,181],{},[30,182,183,186],{},[33,184,185],{},"Command",[33,187,188],{},"Action",[40,190,191,201,211,221,231,241,251,261,271,281],{},[30,192,193,198],{},[45,194,195],{},[103,196,197],{},"collectNow",[45,199,200],{},"Trigger immediate collection cycle",[30,202,203,208],{},[45,204,205],{},[103,206,207],{},"screenshot",[45,209,210],{},"Capture and submit screenshot",[30,212,213,218],{},[45,214,215],{},[103,216,217],{},"changeLayout",[45,219,220],{},"Switch to a specific layout",[30,222,223,228],{},[45,224,225],{},[103,226,227],{},"overlayLayout",[45,229,230],{},"Show a layout as overlay",[30,232,233,238],{},[45,234,235],{},[103,236,237],{},"revertToSchedule",[45,239,240],{},"Return to scheduled layout",[30,242,243,248],{},[45,244,245],{},[103,246,247],{},"purgeAll",[45,249,250],{},"Clear cache and re-download",[30,252,253,258],{},[45,254,255],{},[103,256,257],{},"dataUpdate",[45,259,260],{},"Refresh dataset\u002Fconnector data",[30,262,263,268],{},[45,264,265],{},[103,266,267],{},"commandAction",[45,269,270],{},"Execute a CMS-defined command",[30,272,273,278],{},[45,274,275],{},[103,276,277],{},"triggerWebhook",[45,279,280],{},"Trigger interactive action",[30,282,283,288],{},[45,284,285],{},[103,286,287],{},"criteriaUpdate",[45,289,290],{},"Update display criteria",[15,292,293],{},"XMR uses RSA key exchange + ARC4 symmetric encryption. Auto-reconnect with exponential backoff (10 attempts).",[19,295,297],{"id":296},"rendering-pipeline","Rendering pipeline",[82,299,301],{"id":300},"xlf-xibo-layout-format","XLF (Xibo Layout Format)",[15,303,304],{},"Layouts are XML files defining regions, widgets, and transitions:",[306,307,312],"pre",{"className":308,"code":309,"language":310,"meta":311,"style":311},"language-xml shiki shiki-themes material-theme-lighter github-light github-dark","\u003Clayout width=\"1920\" height=\"1080\" background=\"bg.jpg\">\n  \u003Cregion id=\"1\" width=\"1920\" height=\"1080\" top=\"0\" left=\"0\">\n    \u003Cmedia id=\"42\" type=\"video\" duration=\"30\" uri=\"video.mp4\">\n      \u003Coptions>\u003Cloop>1\u003C\u002Floop>\u003C\u002Foptions>\n    \u003C\u002Fmedia>\n    \u003Cmedia id=\"43\" type=\"image\" duration=\"10\" uri=\"image.jpg\">\n      \u003Coptions>\u003CscaleType>center\u003C\u002FscaleType>\u003C\u002Foptions>\n    \u003C\u002Fmedia>\n  \u003C\u002Fregion>\n\u003C\u002Flayout>\n","xml","",[103,313,314,371,437,495,528,538,591,618,627,637],{"__ignoreMap":311},[315,316,319,323,327,331,334,338,342,344,347,349,351,354,356,359,361,363,366,368],"span",{"class":317,"line":318},"line",1,[315,320,322],{"class":321},"sP7_E","\u003C",[315,324,326],{"class":325},"sQzsp","layout",[315,328,330],{"class":329},"s9AJx"," width",[315,332,333],{"class":321},"=",[315,335,337],{"class":336},"sjJ54","\"",[315,339,341],{"class":340},"s_sjI","1920",[315,343,337],{"class":336},[315,345,346],{"class":329}," height",[315,348,333],{"class":321},[315,350,337],{"class":336},[315,352,353],{"class":340},"1080",[315,355,337],{"class":336},[315,357,358],{"class":329}," background",[315,360,333],{"class":321},[315,362,337],{"class":336},[315,364,365],{"class":340},"bg.jpg",[315,367,337],{"class":336},[315,369,370],{"class":321},">\n",[315,372,374,377,380,383,385,387,390,392,394,396,398,400,402,404,406,408,410,412,415,417,419,422,424,427,429,431,433,435],{"class":317,"line":373},2,[315,375,376],{"class":321},"  \u003C",[315,378,379],{"class":325},"region",[315,381,382],{"class":329}," id",[315,384,333],{"class":321},[315,386,337],{"class":336},[315,388,389],{"class":340},"1",[315,391,337],{"class":336},[315,393,330],{"class":329},[315,395,333],{"class":321},[315,397,337],{"class":336},[315,399,341],{"class":340},[315,401,337],{"class":336},[315,403,346],{"class":329},[315,405,333],{"class":321},[315,407,337],{"class":336},[315,409,353],{"class":340},[315,411,337],{"class":336},[315,413,414],{"class":329}," top",[315,416,333],{"class":321},[315,418,337],{"class":336},[315,420,421],{"class":340},"0",[315,423,337],{"class":336},[315,425,426],{"class":329}," left",[315,428,333],{"class":321},[315,430,337],{"class":336},[315,432,421],{"class":340},[315,434,337],{"class":336},[315,436,370],{"class":321},[315,438,440,443,446,448,450,452,455,457,460,462,464,467,469,472,474,476,479,481,484,486,488,491,493],{"class":317,"line":439},3,[315,441,442],{"class":321},"    \u003C",[315,444,445],{"class":325},"media",[315,447,382],{"class":329},[315,449,333],{"class":321},[315,451,337],{"class":336},[315,453,454],{"class":340},"42",[315,456,337],{"class":336},[315,458,459],{"class":329}," type",[315,461,333],{"class":321},[315,463,337],{"class":336},[315,465,466],{"class":340},"video",[315,468,337],{"class":336},[315,470,471],{"class":329}," duration",[315,473,333],{"class":321},[315,475,337],{"class":336},[315,477,478],{"class":340},"30",[315,480,337],{"class":336},[315,482,483],{"class":329}," uri",[315,485,333],{"class":321},[315,487,337],{"class":336},[315,489,490],{"class":340},"video.mp4",[315,492,337],{"class":336},[315,494,370],{"class":321},[315,496,498,501,504,507,510,513,516,519,521,524,526],{"class":317,"line":497},4,[315,499,500],{"class":321},"      \u003C",[315,502,503],{"class":325},"options",[315,505,506],{"class":321},">\u003C",[315,508,509],{"class":325},"loop",[315,511,512],{"class":321},">",[315,514,389],{"class":515},"su5hD",[315,517,518],{"class":321},"\u003C\u002F",[315,520,509],{"class":325},[315,522,523],{"class":321},">\u003C\u002F",[315,525,503],{"class":325},[315,527,370],{"class":321},[315,529,531,534,536],{"class":317,"line":530},5,[315,532,533],{"class":321},"    \u003C\u002F",[315,535,445],{"class":325},[315,537,370],{"class":321},[315,539,541,543,545,547,549,551,554,556,558,560,562,565,567,569,571,573,576,578,580,582,584,587,589],{"class":317,"line":540},6,[315,542,442],{"class":321},[315,544,445],{"class":325},[315,546,382],{"class":329},[315,548,333],{"class":321},[315,550,337],{"class":336},[315,552,553],{"class":340},"43",[315,555,337],{"class":336},[315,557,459],{"class":329},[315,559,333],{"class":321},[315,561,337],{"class":336},[315,563,564],{"class":340},"image",[315,566,337],{"class":336},[315,568,471],{"class":329},[315,570,333],{"class":321},[315,572,337],{"class":336},[315,574,575],{"class":340},"10",[315,577,337],{"class":336},[315,579,483],{"class":329},[315,581,333],{"class":321},[315,583,337],{"class":336},[315,585,586],{"class":340},"image.jpg",[315,588,337],{"class":336},[315,590,370],{"class":321},[315,592,594,596,598,600,603,605,608,610,612,614,616],{"class":317,"line":593},7,[315,595,500],{"class":321},[315,597,503],{"class":325},[315,599,506],{"class":321},[315,601,602],{"class":325},"scaleType",[315,604,512],{"class":321},[315,606,607],{"class":515},"center",[315,609,518],{"class":321},[315,611,602],{"class":325},[315,613,523],{"class":321},[315,615,503],{"class":325},[315,617,370],{"class":321},[315,619,621,623,625],{"class":317,"line":620},8,[315,622,533],{"class":321},[315,624,445],{"class":325},[315,626,370],{"class":321},[315,628,630,633,635],{"class":317,"line":629},9,[315,631,632],{"class":321},"  \u003C\u002F",[315,634,379],{"class":325},[315,636,370],{"class":321},[315,638,640,642,644],{"class":317,"line":639},10,[315,641,518],{"class":321},[315,643,326],{"class":325},[315,645,370],{"class":321},[82,647,649],{"id":648},"widget-types","Widget types",[24,651,652,665],{},[27,653,654],{},[30,655,656,659,662],{},[33,657,658],{},"Type",[33,660,661],{},"Element",[33,663,664],{},"Special handling",[40,666,667,680,693,706,717,730,742],{},[30,668,669,672,677],{},[45,670,671],{},"Video",[45,673,674],{},[103,675,676],{},"\u003Cvideo>",[45,678,679],{},"HLS.js for non-Safari, pause-on-last-frame",[30,681,682,685,690],{},[45,683,684],{},"Image",[45,686,687],{},[103,688,689],{},"\u003Cimg>",[45,691,692],{},"scaleType (center\u002Fstretch\u002Ffit), align\u002Fvalign",[30,694,695,698,703],{},[45,696,697],{},"Audio",[45,699,700],{},[103,701,702],{},"\u003Caudio>",[45,704,705],{},"Gradient visualization overlay",[30,707,708,711,714],{},[45,709,710],{},"PDF",[45,712,713],{},"Canvas",[45,715,716],{},"PDF.js (lazy-loaded), page-by-page rendering",[30,718,719,722,727],{},[45,720,721],{},"Text\u002FTicker",[45,723,724],{},[103,725,726],{},"\u003Ciframe>",[45,728,729],{},"GetResource from CMS, NUMITEMS\u002FDURATION parsing",[30,731,732,735,739],{},[45,733,734],{},"Web page",[45,736,737],{},[103,738,726],{},[45,740,741],{},"Direct src, sandboxed",[30,743,744,747,751],{},[45,745,746],{},"All CMS widgets",[45,748,749],{},[103,750,726],{},[45,752,753],{},"Generic GetResource rendering",[82,755,757],{"id":756},"performance-optimizations","Performance optimizations",[159,759,760,770,776,782,791],{},[100,761,762,765,766,769],{},[92,763,764],{},"Element reuse"," — widgets are pre-created and toggled via ",[103,767,768],{},"visibility",", not destroyed\u002Frecreated",[100,771,772,775],{},[92,773,774],{},"2-layout preload pool"," — next layout pre-built at 75% of current duration",[100,777,778,781],{},[92,779,780],{},"Blob URL lifecycle"," — tracked and revoked to prevent memory leaks",[100,783,784,787,788],{},[92,785,786],{},"Parallel media prefetch"," — all widget media URLs fetched via ",[103,789,790],{},"Promise.all",[100,792,793,796],{},[92,794,795],{},"Media-ready gating"," — layout timer starts only when all first widgets are loaded",[19,798,800],{"id":799},"download-system","Download system",[82,802,804],{"id":803},"chunked-parallel-downloads","Chunked parallel downloads",[15,806,807],{},"Large files are split into 4 parallel 50MB chunks:",[306,809,814],{"className":810,"code":812,"language":813},[811],"language-text","File: 200MB video.mp4\n  Chunk 1: bytes 0-49999999      (parallel)\n  Chunk 2: bytes 50000000-99999999   (parallel)\n  Chunk 3: bytes 100000000-149999999 (parallel)\n  Chunk 4: bytes 150000000-199999999 (parallel)\n  → Reassemble → MD5 verify → Store\n","text",[103,815,812],{"__ignoreMap":311},[159,817,818,824,830,836],{},[100,819,820,823],{},[92,821,822],{},"Header+trailer first"," — downloads first and last 1MB of MP4 for instant playback start",[100,825,826,829],{},[92,827,828],{},"Resume"," — incomplete downloads resume from last successful chunk",[100,831,832,835],{},[92,833,834],{},"Download windows"," — CMS-configured time restrictions honored",[100,837,838,841],{},[92,839,840],{},"Urgent queue"," — current layout media gets priority over background downloads",[82,843,845],{"id":844},"storage-layers","Storage layers",[24,847,848,861],{},[27,849,850],{},[30,851,852,855,858],{},[33,853,854],{},"Layer",[33,856,857],{},"Technology",[33,859,860],{},"Use case",[40,862,863,874,885],{},[30,864,865,868,871],{},[45,866,867],{},"ContentStore",[45,869,870],{},"Filesystem via proxy",[45,872,873],{},"Media files, layouts (Electron\u002FChromium)",[30,875,876,879,882],{},[45,877,878],{},"Service Worker",[45,880,881],{},"Cache API",[45,883,884],{},"Media files (PWA)",[30,886,887,890,893],{},[45,888,889],{},"IndexedDB",[45,891,892],{},"Structured data",[45,894,895],{},"Schedule, settings, stats, logs, file metadata",[19,897,899],{"id":898},"schedule-system","Schedule system",[82,901,903],{"id":902},"priority-resolution","Priority resolution",[306,905,908],{"className":906,"code":907,"language":813},[811],"1. Interrupt layouts (share of voice, percentage-based)\n2. Campaign layouts (highest priority wins)\n3. Default layout (lowest priority fallback)\n",[103,909,907],{"__ignoreMap":311},[15,911,912],{},"Within the same priority: layouts cycle in order with configurable duration.",[82,914,916],{"id":915},"dayparting","Dayparting",[159,918,919,922,925,928],{},[100,920,921],{},"Daily, weekly, monthly recurrence",[100,923,924],{},"Midnight-crossing support (e.g., 22:00 → 06:00)",[100,926,927],{},"Geo-fencing with location fallback chain (browser → Google API → IP)",[100,929,930],{},"Weather criteria evaluation",[82,932,934],{"id":933},"layout-blacklist","Layout blacklist",[15,936,937],{},"Layouts that fail rendering 3 consecutive times are blacklisted and reported to CMS via the BlackList XMDS method. Blacklist resets when RequiredFiles changes.",[19,939,941],{"id":940},"multi-display-sync","Multi-display sync",[15,943,944,945,949],{},"See ",[48,946,948],{"href":947},"\u002Fdocs\u002Fsdk\u002Fmulti-display","Multi-Display Video Walls"," for the complete setup guide.",[15,951,952,157],{},[92,953,954],{},"Protocol summary",[159,956,957,964,970,976],{},[100,958,959,960,963],{},"Lead broadcasts ",[103,961,962],{},"layout-change"," with target timestamp",[100,965,966,967],{},"Followers preload → report ",[103,968,969],{},"ready",[100,971,959,972,975],{},[103,973,974],{},"layout-show"," at coordinated timestamp",[100,977,978],{},"All displays show simultaneously (±4ms measured, \u003C8ms guaranteed)",[19,980,982],{"id":981},"testing","Testing",[24,984,985,998],{},[27,986,987],{},[30,988,989,992,995],{},[33,990,991],{},"Suite",[33,993,994],{},"Count",[33,996,997],{},"Framework",[40,999,1000,1011,1022,1033,1044,1055,1065,1076],{},[30,1001,1002,1005,1008],{},[45,1003,1004],{},"SDK unit tests",[45,1006,1007],{},"1744",[45,1009,1010],{},"Vitest + jsdom",[30,1012,1013,1016,1019],{},[45,1014,1015],{},"Electron unit",[45,1017,1018],{},"20",[45,1020,1021],{},"Vitest",[30,1023,1024,1027,1030],{},[45,1025,1026],{},"Electron e2e",[45,1028,1029],{},"7",[45,1031,1032],{},"Playwright",[30,1034,1035,1038,1041],{},[45,1036,1037],{},"Chromium",[45,1039,1040],{},"9",[45,1042,1043],{},"bats",[30,1045,1046,1049,1052],{},[45,1047,1048],{},"arexibo",[45,1050,1051],{},"18",[45,1053,1054],{},"Rust cargo test",[30,1056,1057,1060,1062],{},[45,1058,1059],{},"Android",[45,1061,1040],{},[45,1063,1064],{},"JUnit + Robolectric",[30,1066,1067,1070,1073],{},[45,1068,1069],{},"webOS",[45,1071,1072],{},"11",[45,1074,1075],{},"Node.js test runner",[30,1077,1078,1083,1088],{},[45,1079,1080],{},[92,1081,1082],{},"Total",[45,1084,1085],{},[92,1086,1087],{},"1818",[45,1089],{},[15,1091,1092],{},"Integration tests run nightly against the dev CMS via Docker Compose or direct connection.",[1094,1095,1096],"style",{},"html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sQzsp, html code.shiki .sQzsp{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .s9AJx, html code.shiki .s9AJx{--shiki-light:#9C3EDA;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":311,"searchDepth":439,"depth":439,"links":1098},[1099,1100,1104,1109,1113,1118,1119],{"id":21,"depth":373,"text":22},{"id":79,"depth":373,"text":80,"children":1101},[1102,1103],{"id":84,"depth":439,"text":85},{"id":172,"depth":439,"text":173},{"id":296,"depth":373,"text":297,"children":1105},[1106,1107,1108],{"id":300,"depth":439,"text":301},{"id":648,"depth":439,"text":649},{"id":756,"depth":439,"text":757},{"id":799,"depth":373,"text":800,"children":1110},[1111,1112],{"id":803,"depth":439,"text":804},{"id":844,"depth":439,"text":845},{"id":898,"depth":373,"text":899,"children":1114},[1115,1116,1117],{"id":902,"depth":439,"text":903},{"id":915,"depth":439,"text":916},{"id":933,"depth":439,"text":934},{"id":940,"depth":373,"text":941},{"id":981,"depth":373,"text":982},"Complete technical reference for the xiboplayer SDK and player ecosystem","md",{"order":530},true,"\u002Fdocs\u002Fsdk\u002Ftechnical-manual",{"title":5,"description":1120},"docs\u002Fsdk\u002Ftechnical-manual","OMt2VA2CA3fZOUXpR981CNYuQPU6GRLte5d52Pgl-HE",1775148113007]