התחברות

WebSocket בזמן אמת

שליטה בחדר Cliqer מהתוכנה שלכם כמו בשלט למצגות מרחוק: שקפים, טיימר, סמן לייזר והודעות למארח

התחברו אל wss://cliqer.io/ws כדי לשלוט בחדר Cliqer מהתוכנה שלכם או ממערכת בקרת המופע שלכם, כמו בשלט למצגות מרחוק: החלפת שקפים, הפעלת הטיימר של המארח, הצבעה עם נקודת לייזר ושליחת הודעות למארח. האפליקציה שלכם מצטרפת לחדר כמציג; את החדר עצמו מארחת תמיד אפליקציית שולחן העבודה של Cliqer.

אימות: יש להתחבר עם אסימון סשן: קובץ ה-cookie‏ session_token (דפדפנים שולחים אותו אוטומטית), פרמטר השאילתה ?token= או הכותרת Authorization: Bearer. האסימון נבדק בעת ההתחברות ולא בכל פקודה, ולכן כשתוקפו פג יש לפתוח חיבור חדש עם אסימון חדש ולהצטרף שוב. ללא אסימון אפשר להתחבר, אך אי אפשר להשתמש ב-API. מפתחות API של הצוות (cliqer_...) מאמתים רק את נקודות הקצה של REST; ב-socket הזה מפתח אינו אסימון סשן.

חיבור

# WebSocket connections require a WebSocket client
# Using websocat for testing:
websocat "$WS_URL/ws?token=YOUR_ACCESS_TOKEN"

השרת שולח connected עם ה-clientId שלכם לאחר שהגדיר את החיבור. יש להמתין לו לפני שליחת כל דבר: הודעה שמגיעה לפני כן נדחית עם error והחיבור נסגר.


זרימת החיבור והחדר

ניווט בשקפים

שליטה בשקפים בחדר מהתוכנה שלכם, כמו בשלט למצגות מרחוק. האפליקציה שלכם מצטרפת לחדר כמציג, כך שהמארח רואה אותה ברשימת המציגים תחת ה-presenterName שלה ושולט בה כמו בכל מציג: המפעיל יכול לכבות את הלחיצות שלה, להסיר אותה או לחסום אותה.

  • יש להתחבר עם אסימון סשן (?token=, הכותרת Authorization: Bearer או קובץ ה-cookie‏ session_token). מפתחות API של הצוות פועלים רק בנקודות הקצה של REST, לא ב-socket הזה.
  • התוכנית של בעל החדר חייבת לכלול את ה-Client API: תוסף ה-API בתוכניות Presenter,‏ Studio HD ו-Studio 4K, וכלול בתוכניות Studio 8K ו-Enterprise.
  • פקודות שקפים וטיימר פועלות רק כל עוד המארח מאפשר לחיצות מהחיבור שלכם.

הצטרפות לחדר

{ "type": "joinRoom", "payload": { "room": "ABC123", "presenterName": "Show control", "api": true } }
  • יש לשלוח אותה אחרי האירוע connected: השרת דוחה כל דבר שמגיע לפניו.
  • presenterName הוא השם שהמארח רואה (ברירת המחדל: API). האפליקציה שלכם היא תמיד מציג בחדר, ואף פעם לא המארח שלו.
  • יש להמתין לאירוע clicksEnabled עם payload‏ true לפני שליחת פקודות. המארח שולח אותו לאחר שהגדיר את החיבור שלכם, ושוב בכל פעם שהמפעיל מפעיל או מכבה את הלחיצות שלכם.
  • שמרו את ה-presenterKey מ-joinedRoom ושלחו אותו ב-joinRoom בעת התחברות מחדש, כדי שהמארח ישמור על הרשאת הלחיצות שלכם.
  • שלחו את מסגרת הטקסט ping כל 15 שניות כדי לשמור על החיבור פתוח. השרת עונה במסגרת הטקסט pong (לא JSON).

שליחת פקודות

{ "type": "webAction", "payload": { "action": "goto", "slide": 5, "id": "a3" } }
actionשדה נוסףמה זה עושה
nextהשקף הבא (או שלב ההנפשה הבא)
prevהשקף הקודם (או שלב ההנפשה הקודם)
firstהשקף הראשון
lastהשקף האחרון
gotoslide: מספר שלם מ-1 עד 9999מעבר לשקף הזה
blackouton: true או falseהשחרת המסך, או הצגתו שוב
  • id הוא אופציונלי: 1 עד 64 אותיות, ספרות, _, ., : או -. הוא חוזר בתוצאה. השתמשו ב-id חדש לכל פקודה: המארח מתעלם מפקודה שאת ה-id שלה כבר קיבל מהחיבור שלכם ב-5 השניות האחרונות, כך שניסיון חוזר של אותה פקודה מתבצע פעם אחת בלבד.
  • first, last, goto ו-blackout פועלות רק במארח שאירוע ה-controls האחרון שלו מפרט אותן ב-nav. מארח שאינו שולח אירוע controls תומך ב-next וב-prev בלבד. כשיש כמה מארחים בחדר, כל מארח מבצע את הפקודות שהוא תומך בהן.
  • next או prev בזמן שהמסך מושחר מציגות אותו שוב בלי לזוז.
  • המערכת מתעלמת מ-goto אל מעבר לשקף האחרון.
  • שלחו לכל היותר 10 פקודות בשנייה, פקודות שקפים וטיימר יחד. המארח גם מתעלם מחזרה על אותה פקודה בתוך 50 מילישניות.

מה כל אפליקציית מצגות תומכת בו כיום:

אפליקציית מצגותnext, prevfirst, lastgotoblackout
PowerPoint ב-Windowsכןכןכןכן
PowerPoint ב-Macכןכןלאלא
Keynoteכןלאלאכן
Google Slides (עם תוסף הדפדפן מחובר)כןכןלאלא
vMixכןלאלאלא
חלון ממוקדכןלאלאלא

אירוע ה-controls הוא התשובה העדכנית עבור המארח שבו אתם שולטים: יש לקרוא את nav ממנו ולא מהטבלה הזו.

# One connection: wait for `connected`, join as an API client, give the host a
# moment to set it up, then send commands. Replies print as they arrive.
( sleep 2
  echo '{"type":"joinRoom","payload":{"room":"ABC123","presenterName":"Show control","api":true}}'
  sleep 3
  echo '{"type":"webAction","payload":{"action":"next","id":"a1"}}'
  sleep 1
  echo '{"type":"webAction","payload":{"action":"prev","id":"a2"}}'
  sleep 1 ) | websocat "$WS_URL/ws?token=YOUR_SESSION_TOKEN"

תוצאות ואירועים

כל פקודה נענית ב-webActionResult או ב-error.

{ "type": "webActionResult", "payload": { "action": "next", "id": "a1", "hosts": 1 } }

hosts הוא מספר המארחים שהפקודה נמסרה אליהם. ההוכחה שהיא בוצעה היא אירוע ה-slide הבא של המארח; blackout משנה גם את blackout באירוע ה-controls הבא של המארח. פקודה שהמארח אינו מבצע (לחיצות כבויות, פקודה שהוא אינו תומך בה, goto אל מעבר לשקף האחרון) מקבלת תוצאה, אך לא אירוע slide.

errorמתי
auth_requiredjoinRoom עם api: true בחיבור ללא אסימון סשן
not_api_clientפקודה מחיבור שלא הצטרף לחדר עם api: true, או אחרי שעזב אותו
invalid_web_actionaction לא מוכר, או slide, on או id חסר או לא תקין
invalid_timer_actionaction טיימר לא מוכר, או minutes או id חסר או לא תקין
invalid_messageהודעה ללא text, או ארוכה מ-1000 תווים
invalid_presenter_mouseמיקום סמן מחוץ לטווח 0 עד 1
rate_limitedיותר מ-10 פקודות שקפים וטיימר בשנייה אחת, או יותר מ-5 הודעות ב-10 שניות
no_hostאין מארח מחובר לחדר
host_update_requiredכל המארחים בחדר מריצים גרסה ישנה של Cliqer שאינה יכולה לקבל פקודות מה-API
api_not_in_planהתוכנית של בעל החדר אינה כוללת את ה-Client API

שגיאות כוללות message קריא, וכשהפקודה הייתה בנויה כהלכה, גם את ה-action וה-id שלה:

{ "type": "error", "error": "invalid_web_action", "payload": { "message": "Unknown or incomplete webAction. Use next, prev, first, last, goto with slide, or blackout with on.", "action": "goto", "id": "a3" } }

אירועים ממארח נושאים את המזהה של אותו מארח ב-hostId:

אירועתוכן
clicksEnabledtrue כשהמארח מקבל את הפקודות שלכם, false כשהמפעיל כיבה את הלחיצות שלכם
controls{ app, nav, blackout, timer }: אפליקציית המצגות, פקודות השקפים הנוספות שהיא תומכת בהן (first, last, goto, blackout), האם המסך מושחר, והאם המארח מקבל פקודות טיימר
slide{ number, current, total, title, notes } אחרי כל פקודה שהמארח ביצע (number הוא "4/12", ו-total הוא null כשהאפליקציה אינה מדווחת עליו), או null כשאין למארח מצגת פתוחה
countdownהזמן שהטיימר של המארח מציג, למשל "4:59" ("-0:12" בחריגה מהזמן), בכל שנייה בזמן שהוא פועל, או null כשהוא נעצר
countdownPhase{ phase, blink }: phase הוא idle, talk, warning (נותרה פחות מדקה), overtime או paused, ו-blink מציין אם הטיימר של המארח מהבהב
messageFromHostתשובה ממפעיל המארח, ראו הודעות למארח

תקבלו גם את האירועים של החדר עצמו (clientJoined, clientLeft ואחרים); אפשר להתעלם מאלה שאינכם משתמשים בהם. אם המפעיל מסיר או חוסם את החיבור שלכם, תקבלו logout עם reason: "kicked".

טיימר

הפעלת הטיימר באפליקציית Cliqer של המארח באמצעות אותן פקודות ש-Stream Deck או Bitfocus Companion שולחים.

{ "type": "timerAction", "payload": { "action": "set", "minutes": 25, "id": "t1" } }
actionמה זה עושה
startהפעלת הטיימר, או המשך אחרי stop
stopהשהיית הטיימר
resetעצירת הטיימר וחזרה לזמן שהוגדר בו
plus1, plus2, plus5הוספת 1, 2 או 5 דקות
minus1, minus2, minus5הפחתת 1, 2 או 5 דקות
preset5, preset10, preset15, preset20עצירת הטיימר והגדרת 5, 10, 15 או 20 דקות
setעצירת הטיימר והגדרת minutes, מספר שלם מ-1 עד 999
  • כל פקודה נענית ב-timerActionResult ({ action, id, hosts }, ו-hosts כמו בשקפים) או ב-error. ההוכחה שהיא בוצעה היא אירוע ה-countdown או ה-countdownPhase הבא של המארח.
  • הטיימר פועל רק במארח שאירוע ה-controls האחרון שלו כולל timer: true. מארחים בגרסה ישנה של Cliqer אינם מכריזים על כך ומתעלמים מפקודות טיימר.
  • פקודות טיימר כפופות לאותם כללים כמו פקודות שקפים: המארח מבצע אותן רק כל עוד הוא מאפשר לחיצות מהחיבור שלכם, והן חולקות את המכסה של 10 פקודות בשנייה.
  • הגדרות הטיימר של המארח חלות כפי שהן: טיימר שמוגדר לספירה עולה סופר כלפי מעלה, וטיימר שעוקב אחר טיימר חומרה מחובר לוקח את הזמן שלו מאותו התקן.

סמן לייזר

הצגת נקודת לייזר על המסך המשותף של המארח, בדיוק כמו מהטלפון של מציג.

{ "type": "presenterMouse", "payload": { "mouse": { "x": 0.5, "y": 0.25 } } }
  • x ו-y הם המיקום על המסך המשותף ביחס לפינה השמאלית העליונה שלו, מ-0 עד 1.
  • שלחו { "pressed": false } כ-payload כדי להסתיר את הנקודה. אחרת היא נעלמת 30 עד 90 שניות אחרי המיקום האחרון ששלחתם.
  • הנקודה מוצגת רק כשהמארח משתף מסך והאפשרות סמן לייזר מופעלת אצלו. הצבע שלה נקבע לפי ה-presenterName שלכם.
  • שלחו לכל היותר 30 מיקומים בשנייה. מיקומים עודפים נזרקים ללא שגיאה, ואין אירוע תוצאה.

הודעות למארח

שליחת הודעה למפעיל המארח. היא מופיעה בצ'אט המציגים של המארח, בדיוק כמו הודעה מהטלפון של מציג, ותשובות המפעיל חוזרות כ-messageFromHost.

# Join as an API client, then send a message. Replies print as they arrive.
( sleep 2
  echo '{"type":"joinRoom","payload":{"room":"ABC123","presenterName":"Show control","api":true}}'
  sleep 3
  echo '{"type":"messageToHosts","payload":{"text":"Two minutes to the break","id":"m1"}}'
  sleep 30 ) | websocat "$WS_URL/ws?token=YOUR_SESSION_TOKEN"

תשובה מהמארח:

{
  "type": "messageFromHost",
  "payload": {
    "fromClientId": "host_abc123",
    "fromPresenterName": "Stage PC",
    "originalPayload": { "text": "Thanks, got it" }
  },
  "hostId": "host_abc123"
}
  • אורך text הוא 1 עד 1000 תווים. שלחו לכל היותר 5 הודעות בכל 10 שניות.
  • כל הודעה נענית ב-messageToHostsResult ({ id, hosts }) או ב-error.
  • המפעיל רואה את ההודעה תחת ה-presenterName שלכם, והמארח מציג התראה כשההגדרה התראות שלו מופעלת.

מדריך אירועים

אירועים יוצאים (לקוח → שרת)

אירועתיאור
joinRoomהצטרפות לחדר כלקוח API עם api: true (ראו ניווט בשקפים)
webActionשליטה בשקפים (ראו ניווט בשקפים)
timerActionשליטה בטיימר (ראו טיימר)
presenterMouseמיקום סמן הלייזר (ראו סמן לייזר)
messageToHostsשליחת הודעה למפעיל המארח (ראו הודעות למארח)
logoutיציאה מהחדר; החיבור נשאר פתוח ואפשר להצטרף שוב

אירועים נכנסים (שרת → לקוח)

אירועתיאור
connectedנשלח עם פתיחת החיבור, עם { clientId, userId, isAuthenticated }
joinedRoomההצטרפות לחדר הצליחה
clientJoinedמישהו הצטרף לחדר
clientLeftמישהו עזב את החדר
webActionResultwebAction נמסר למארחי החדר
timerActionResulttimerAction נמסר למארחי החדר
messageToHostsResultmessageToHosts נמסר למארחי החדר
clicksEnabledהאם מארח מקבל את הפקודות שלכם
controlsבמה תומכים אפליקציית המצגות והטיימר של מארח
slideהשקף הנוכחי של מארח אחרי פקודה
countdownהזמן בטיימר של מארח
countdownPhaseהשלב של הטיימר של מארח
messageFromHostהודעה ממפעיל המארח
logoutהמפעיל הסיר או חסם את החיבור שלכם (reason: "kicked")
errorהודעת שגיאה