├── .gitignore ├── DeskPro_BeRightBack ├── DeskPro_BeRightBack.js └── README.md ├── DeskPro_ImmersiveComposing ├── DeskPro_ImmersiveComposing.js ├── DeskPro_ImmersiveComposing.xml ├── README.md └── images │ ├── immersiveVideo.png │ ├── presentationComposing.png │ ├── videoComposing.png │ └── webexSpaceQR.png ├── DeskPro_ImmersiveVideo ├── DeskPro_ImmersiveVideo.js ├── DeskPro_ImmersiveVideo.xml └── README.md ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /DeskPro_BeRightBack/DeskPro_BeRightBack.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Christian Wolf 3 | * @copyright Copyright (c) 2022 Cisco and/or its affiliates. 4 | * @license Cisco Sample Code License, Version 1.1 5 | */ 6 | 7 | /** 8 | * @license 9 | * Copyright (c) 2022 Cisco and/or its affiliates. 10 | * 11 | * This software is licensed to you under the terms of the Cisco Sample 12 | * Code License, Version 1.1 (the "License"). You may obtain a copy of the 13 | * License at 14 | * 15 | * https://developer.cisco.com/docs/licenses 16 | * 17 | * All use of the material herein must be in accordance with the terms of 18 | * the License. All rights not expressly granted by the License are 19 | * reserved. Unless required by applicable law or agreed to separately in 20 | * writing, software distributed under the License is distributed on an "AS 21 | * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 22 | * or implied. 23 | */ 24 | 25 | import xapi from 'xapi'; 26 | 27 | let cameraLidState; 28 | let backgroundImage; 29 | let backgroundMode; 30 | let muteStatus; 31 | let beRightBack = false; 32 | 33 | async function getInitialSettings() { 34 | backgroundImage = await xapi.Status.Cameras.Background.Image.get(); 35 | backgroundMode = await xapi.Status.Cameras.Background.Mode.get(); 36 | cameraLidState = await xapi.Status.SystemUnit.State.CameraLid.get(); 37 | }; 38 | 39 | async function getMuteStatus() { 40 | muteStatus = await xapi.Status.Audio.Microphones.Mute.get(); 41 | }; 42 | 43 | xapi.on('ready', () => { 44 | getInitialSettings(); 45 | }); 46 | 47 | // Event for Camera lid changes 48 | xapi.status.on('SystemUnit State CameraLid', (status) => { 49 | cameraLidState = status; 50 | }); 51 | 52 | // Event if Background Image or Mode has been changed 53 | xapi.status.on('Cameras Background', (event) => { 54 | if (!beRightBack) { 55 | if (event['Image']) {backgroundImage = event['Image']; } 56 | else {backgroundMode = event['Mode']; }; 57 | }; 58 | }); 59 | 60 | // Event if PeopleCount changes 61 | xapi.status.on('RoomAnalytics PeopleCount Current', (count) => { 62 | if (count === '0' && cameraLidState === 'Open') { 63 | getMuteStatus(); 64 | beRightBack = true; 65 | xapi.command('Cameras Background Set', { Image: 'User1', Mode: 'Image'}); 66 | xapi.command('Audio Microphones Mute'); 67 | } 68 | else if (count === '1') { 69 | beRightBack = false; 70 | if (backgroundMode === 'Image') { xapi.command('Cameras Background Set', { Image: backgroundImage, Mode: backgroundMode }); } 71 | else {xapi.command('Cameras Background Set', { Mode: backgroundMode }); }; 72 | if (muteStatus == 'Off') {xapi.command('Audio Microphones Unmute');}; 73 | }; 74 | }); -------------------------------------------------------------------------------- /DeskPro_BeRightBack/README.md: -------------------------------------------------------------------------------- 1 | # Be Right Back 2 | ### Show meeting participants automatically when you're away from your Cisco Webex DeskPro. 3 | 4 | Did you always had to step away from your DeskPro while in a call and forget to mute yourself? 5 | With **BeRightBack** People Presence will detect if you're away, change your background to an Image you have uploaded to the **User1** slot and mute yourself. 6 | After coming back your background will change to your last setting and your microphone unmuted as well. 7 | 8 | --- 9 | 10 | ## Requirements 11 | 1. Cisco Webex DeskPro 12 | 2. Firmware CE9.15 or newer 13 | 4. Admin user access to endpoint 14 | 15 | ## Setup 16 | 1. Import the macro file **[DeskPro_BeRightBack.js](https://github.com/ChrisW0lf/webex-room-customization/blob/main/DeskPro_BeRightBack/DeskPro_BeRightBack.js)** to the **Macro Editor** of your DeskPro and **Save to System**. 17 | 18 | ## Support&Feedback 19 | Please join this **[Webex Space](https://eurl.io/#Fvo7JcAkQ)** if you need support, have questions or to start some discussions around the macro or functionality: 20 | ![QRCodeToWebexSpace](https://github.com/ChrisW0lf/webex-room-customization/blob/main/DeskPro_ImmersiveComposing/images/webexSpaceQR.png) 21 | 22 | ## Disclaimer 23 | Those examples are only samples and are **NOT guaranteed to be bug free and production quality**. 24 | 25 | The sample macros are meant to: 26 | - Illustrate how to use the CE Macros. 27 | - Serve as an example of the step by step process of building a macro using JavaScript and integration with the Codec XAPI. 28 | 29 | The sample macros are made available to Cisco partners and customers as a convenience to help minimize the cost of Cisco Finesse customizations. Cisco does not permit the use of this library in customer deployments that do not include Cisco Video Endpoint Hardware. 30 | -------------------------------------------------------------------------------- /DeskPro_ImmersiveComposing/DeskPro_ImmersiveComposing.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Magnus Ohnm , Christian Wolf 3 | * @copyright Copyright (c) 2021 Cisco and/or its affiliates. 4 | * @license Cisco Sample Code License, Version 1.1 5 | */ 6 | 7 | /** 8 | * @license 9 | * Copyright (c) 2021 Cisco and/or its affiliates. 10 | * 11 | * This software is licensed to you under the terms of the Cisco Sample 12 | * Code License, Version 1.1 (the "License"). You may obtain a copy of the 13 | * License at 14 | * 15 | * https://developer.cisco.com/docs/licenses 16 | * 17 | * All use of the material herein must be in accordance with the terms of 18 | * the License. All rights not expressly granted by the License are 19 | * reserved. Unless required by applicable law or agreed to separately in 20 | * writing, software distributed under the License is distributed on an "AS 21 | * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 22 | * or implied. 23 | */ 24 | 25 | import xapi from 'xapi'; 26 | 27 | function unsetGUIValue(guiId) { 28 | xapi.command('UserInterface Extensions Widget UnsetValue', { 29 | WidgetId: guiId 30 | }); 31 | } 32 | 33 | function composePresentation(sources) { 34 | xapi.command('Presentation Start', { 35 | ConnectorId: sources, 36 | SendingMode: 'LocalRemote' // Options are LocalOnly or LocalRemote (which starts sharing imediately) 37 | }).catch(exception => { 38 | xapi.command('UserInterface Message TextLine Display', { 39 | Text: exception.message, 40 | duration: 3 41 | }); 42 | }); 43 | } 44 | function composeVideo(sources, parts) { 45 | const layout = (parts[2] === 'e') ? 'equal':'pip' 46 | xapi.command('Video Input SetMainVideoSource', { 47 | ConnectorId: sources, 48 | Layout: layout 49 | }).catch(exception => { 50 | xapi.command('UserInterface Message TextLine Display', { 51 | Text: exception.message, 52 | duration: 3 53 | }); 54 | }); 55 | } 56 | xapi.event.on('UserInterface Extensions Widget Action', event => { 57 | if (event.WidgetId.includes('_compositor') && event.Type === 'released') { 58 | switch (event.WidgetId.replace('_compositor', '')) { 59 | case 'stopPresentation': 60 | xapi.command('Presentation Stop') 61 | break; 62 | case 'presentation-s_1': 63 | const sourcecomboS1 = event.Value; 64 | composePresentation(sourcecomboS1); 65 | unsetGUIValue(event.WidgetId); 66 | break; 67 | case 'presentation-s_2_e_1': 68 | const sourcecomboS2E1 = event.Value.split('-'); 69 | composePresentation(sourcecomboS2E1); 70 | unsetGUIValue(event.WidgetId); 71 | break; 72 | case 'presentation-s_2_e_2': 73 | const sourcecomboS2E2 = event.Value.split('-'); 74 | composePresentation(sourcecomboS2E2); 75 | unsetGUIValue(event.WidgetId); 76 | break; 77 | case 'presentation-s_2_e_3': 78 | const sourcecomboS2E3 = event.Value.split('-'); 79 | composePresentation(sourcecomboS2E3); 80 | unsetGUIValue(event.WidgetId); 81 | break; 82 | case 'presentation-s_3_e_1': 83 | const sourcecomboS3E1 = event.Value.split('-'); 84 | composePresentation(sourcecomboS3E1); 85 | unsetGUIValue(event.WidgetId); 86 | break; 87 | case 'presentation-s_3_e_2': 88 | const sourcecomboS3E2 = event.Value.split('-'); 89 | composePresentation(sourcecomboS3E2); 90 | unsetGUIValue(event.WidgetId); 91 | break; 92 | default: 93 | const parts = event.WidgetId.split('_'); 94 | const videoSourceCombo = event.Value.split('-'); 95 | composeVideo(videoSourceCombo,parts); 96 | unsetGUIValue(event.WidgetId); 97 | } 98 | } 99 | }); -------------------------------------------------------------------------------- /DeskPro_ImmersiveComposing/DeskPro_ImmersiveComposing.xml: -------------------------------------------------------------------------------- 1 | 2 | 1.8 3 | 4 | 2 5 | immersiveComposing 6 | local 7 | Statusbar 8 | Laptop 9 | #FFB400 10 | Immersive Composing 11 | Custom 12 | 13 | Video 14 | 15 | Reset 16 | 17 | reset_compositor 18 | GroupButton 19 | size=4;columns=3 20 | 21 | 22 | 1 23 | CAM (S1) 24 | 25 | 26 | 2 27 | USBC (S2) 28 | 29 | 30 | 3 31 | HDMI (S3) 32 | 33 | 34 | 35 | 36 | 37 | Duo source pip 38 | 39 | s_2_p_1_compositor 40 | GroupButton 41 | size=4 42 | 43 | 44 | 1-2 45 | S1-S2 46 | 47 | 48 | 1-3 49 | S1-S3 50 | 51 | 52 | 53 | 54 | s_2_p_2_compositor 55 | GroupButton 56 | size=4 57 | 58 | 59 | 2-1 60 | S2-S1 61 | 62 | 63 | 2-3 64 | S2-S3 65 | 66 | 67 | 68 | 69 | s_2_p_3_compositor 70 | GroupButton 71 | size=4 72 | 73 | 74 | 3-1 75 | S3-S1 76 | 77 | 78 | 3-2 79 | S3-S2 80 | 81 | 82 | 83 | 84 | 85 | Duo source equal 86 | 87 | s_2_e_1_compositor 88 | GroupButton 89 | size=4 90 | 91 | 92 | 1-2 93 | S1-S2 94 | 95 | 96 | 1-3 97 | S1-S3 98 | 99 | 100 | 101 | 102 | s_2_e_2_compositor 103 | GroupButton 104 | size=4 105 | 106 | 107 | 2-1 108 | S2-S1 109 | 110 | 111 | 2-3 112 | S2-S3 113 | 114 | 115 | 116 | 117 | s_2_e_3_compositor 118 | GroupButton 119 | size=4 120 | 121 | 122 | 3-1 123 | S3-S1 124 | 125 | 126 | 3-2 127 | S3-S2 128 | 129 | 130 | 131 | 132 | 133 | Triple source equal 134 | 135 | s_3_e_1_compositor 136 | GroupButton 137 | size=4 138 | 139 | 140 | 1-2-3 141 | S1-S2-S3 142 | 143 | 144 | 2-3-1 145 | S2-S3-S1 146 | 147 | 148 | 3-1-2 149 | S3-S1-S2 150 | 151 | 152 | 153 | 154 | s_3_e_2_compositor 155 | GroupButton 156 | size=4 157 | 158 | 159 | 2-1-3 160 | S2-S1-S3 161 | 162 | 163 | 3-2-1 164 | S3-S2-S1 165 | 166 | 167 | 1-3-2 168 | S1-S3-S2 169 | 170 | 171 | 172 | 173 | video 174 | hideRowNames=0 175 | 176 | 177 | Presentation 178 | 179 | Presentation 180 | 181 | stopPresentation_compositor 182 | Stop Sharing 183 | Button 184 | size=4 185 | 186 | 187 | 188 | Single source 189 | 190 | presentation-s_1_compositor 191 | GroupButton 192 | size=4 193 | 194 | 195 | 2 196 | USBC (S2) 197 | 198 | 199 | 3 200 | HDMI (S3) 201 | 202 | 203 | 1 204 | CAM (S1) 205 | 206 | 207 | 208 | 209 | 210 | Duo source equal 211 | 212 | presentation-s_2_e_1_compositor 213 | GroupButton 214 | size=4 215 | 216 | 217 | 1-2 218 | S1-S2 219 | 220 | 221 | 1-3 222 | S1-S3 223 | 224 | 225 | 226 | 227 | presentation-s_2_e_2_compositor 228 | GroupButton 229 | size=4 230 | 231 | 232 | 2-1 233 | S2-S1 234 | 235 | 236 | 2-3 237 | S2-S3 238 | 239 | 240 | 241 | 242 | presentation-s_2_e_3_compositor 243 | GroupButton 244 | size=4 245 | 246 | 247 | 3-1 248 | S3-S1 249 | 250 | 251 | 3-2 252 | S3-S2 253 | 254 | 255 | 256 | 257 | 258 | Triple source equal 259 | 260 | presentation-s_3_e_1_compositor 261 | GroupButton 262 | size=4 263 | 264 | 265 | 1-2-3 266 | S1-S2-S3 267 | 268 | 269 | 2-3-1 270 | S2-S3-S1 271 | 272 | 273 | 3-1-2 274 | S3-S1-S2 275 | 276 | 277 | 278 | 279 | presentation-s_3_e_2_compositor 280 | GroupButton 281 | size=4 282 | 283 | 284 | 2-1-3 285 | S2-S1-S3 286 | 287 | 288 | 3-2-1 289 | S3-S2-S1 290 | 291 | 292 | 1-3-2 293 | S1-S3-S2 294 | 295 | 296 | 297 | 298 | presentation 299 | 300 | 301 | 302 | ImmersiveVideo for S1 303 | 304 | Source 305 | 306 | source_immersiveVideo 307 | GroupButton 308 | size=4;columns=2 309 | 310 | 311 | UsbC 312 | USB-C 313 | 314 | 315 | Hdmi 316 | HDMI 317 | 318 | 319 | 320 | 321 | 322 | Immersive Mode 323 | 324 | immersiveMode_immersiveVideo 325 | GroupButton 326 | size=4;columns=3 327 | 328 | 329 | Blend 330 | Blend 331 | 332 | 333 | CameraPip 334 | CameraPip 335 | 336 | 337 | VideoPip 338 | VideoPip 339 | 340 | 341 | 342 | 343 | 344 | Position 345 | 346 | position_immersiveVideo 347 | GroupButton 348 | size=4;columns=3 349 | 350 | 351 | upperLeft 352 | Upper Left 353 | 354 | 355 | upperCenter 356 | Upper Center 357 | 358 | 359 | upperRight 360 | Upper Right 361 | 362 | 363 | lowerLeft 364 | Lower Left 365 | 366 | 367 | lowerCenter 368 | Lower Center 369 | 370 | 371 | lowerRight 372 | Lower Right 373 | 374 | 375 | activate 376 | Activate 377 | 378 | 379 | reset 380 | Reset 381 | 382 | 383 | deactivate 384 | Deactivate 385 | 386 | 387 | 388 | 389 | 390 | Size 391 | 392 | sizeLable_immersiveVideo 393 | ??? 394 | Text 395 | size=1;fontSize=normal;align=center 396 | 397 | 398 | sizeSlider_immersiveVideo 399 | Slider 400 | size=3 401 | 402 | 403 | 404 | Opacity 405 | 406 | opacityLable_immersiveVideo 407 | ??? 408 | Text 409 | size=1;fontSize=normal;align=center 410 | 411 | 412 | opacitySlider_immersiveVideo 413 | Slider 414 | size=3 415 | 416 | 417 | 418 | Position Adjustment 419 | 420 | posAdjustmentPad_immersiveVideo 421 | 422 | DirectionalPad 423 | size=4 424 | 425 | 426 | 427 | Adjustment Range 428 | 429 | posAdjustmentLable_immersiveVideo 430 | ??? 431 | Text 432 | size=1;fontSize=normal;align=center 433 | 434 | 435 | posAdjustmentSlider_immersiveVideo 436 | Slider 437 | size=3 438 | 439 | 440 | immersiveVideo 441 | hideRowNames=0 442 | 443 | 444 | 445 | -------------------------------------------------------------------------------- /DeskPro_ImmersiveComposing/README.md: -------------------------------------------------------------------------------- 1 | # ImmersiveComposing 2 | ### Turn your Cisco Webex DeskPro into a home video studio. 3 | 4 | With this setup you will be able to flexibly decide what you want to show or share. 5 | Choose between different sources and layouts to get the desired output. 6 | With the immersive video part you will be even much more flexible. 7 | 8 | --- 9 | ### Choose the video sources and layout you want to show: 10 | ![Video Page](https://github.com/ChrisW0lf/webex-room-customization/blob/main/DeskPro_ImmersiveComposing/images/videoComposing.png) 11 | 12 | ### Choose the presentation sources and layout you want to share: 13 | ![Presentation Page](https://github.com/ChrisW0lf/webex-room-customization/blob/main/DeskPro_ImmersiveComposing/images/presentationComposing.png) 14 | 15 | ### Enrich the experience with immersive settings: 16 | ![Immersive settings](https://github.com/ChrisW0lf/webex-room-customization/blob/main/DeskPro_ImmersiveComposing/images/immersiveVideo.png) 17 | --- 18 | 19 | ## Requirements 20 | 1. Cisco Webex DeskPro 21 | 2. Firmware CE9.15 or newer 22 | 4. Admin user access to endpoint 23 | 24 | ## Setup 25 | 1. Import the UI file **[DeskPro_ImmersiveComposing.xml](https://github.com/ChrisW0lf/webex-room-customization/blob/main/DeskPro_ImmersiveComposing/DeskPro_ImmersiveComposing.xml)** to the **UI Extensions Editor** of your DeskPro and **Export configuration to video system**. 26 | 2. Import the macro file **[DeskPro_ImmersiveComposing.js](https://github.com/ChrisW0lf/webex-room-customization/blob/main/DeskPro_ImmersiveComposing/DeskPro_ImmersiveComposing.js)** to the **Macro Editor** of your DeskPro and **Save to System**. 27 | 3. To get the **immersive capabilites** import the macro file **[DeskPro_ImmersiveVideo.js](https://github.com/ChrisW0lf/webex-room-customization/blob/main/DeskPro_ImmersiveVideo/DeskPro_ImmersiveVideo.js)** to the **Macro Editor**, too. 28 | 29 | ## Support&Feedback 30 | Please join this **[Webex Space](https://eurl.io/#Fvo7JcAkQ)** if you need support, have questions or to start some discussions around the macro or functionality: 31 | ![QRCodeToWebexSpace](https://github.com/ChrisW0lf/webex-room-customization/blob/main/DeskPro_ImmersiveComposing/images/webexSpaceQR.png) 32 | 33 | ## Disclaimer 34 | Those examples are only samples and are **NOT guaranteed to be bug free and production quality**. 35 | 36 | The sample macros are meant to: 37 | - Illustrate how to use the CE Macros. 38 | - Serve as an example of the step by step process of building a macro using JavaScript and integration with the Codec XAPI. 39 | 40 | The sample macros are made available to Cisco partners and customers as a convenience to help minimize the cost of Cisco Finesse customizations. Cisco does not permit the use of this library in customer deployments that do not include Cisco Video Endpoint Hardware. 41 | -------------------------------------------------------------------------------- /DeskPro_ImmersiveComposing/images/immersiveVideo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChrisW0lf/webex-room-customization/3269bfc7d8cf42efd7b39c09adb7daffb771e7d9/DeskPro_ImmersiveComposing/images/immersiveVideo.png -------------------------------------------------------------------------------- /DeskPro_ImmersiveComposing/images/presentationComposing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChrisW0lf/webex-room-customization/3269bfc7d8cf42efd7b39c09adb7daffb771e7d9/DeskPro_ImmersiveComposing/images/presentationComposing.png -------------------------------------------------------------------------------- /DeskPro_ImmersiveComposing/images/videoComposing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChrisW0lf/webex-room-customization/3269bfc7d8cf42efd7b39c09adb7daffb771e7d9/DeskPro_ImmersiveComposing/images/videoComposing.png -------------------------------------------------------------------------------- /DeskPro_ImmersiveComposing/images/webexSpaceQR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChrisW0lf/webex-room-customization/3269bfc7d8cf42efd7b39c09adb7daffb771e7d9/DeskPro_ImmersiveComposing/images/webexSpaceQR.png -------------------------------------------------------------------------------- /DeskPro_ImmersiveVideo/DeskPro_ImmersiveVideo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Christian Wolf 3 | * @copyright Copyright (c) 2021 Cisco and/or its affiliates. 4 | * @license Cisco Sample Code License, Version 1.1 5 | */ 6 | 7 | /** 8 | * @license 9 | * Copyright (c) 2021 Cisco and/or its affiliates. 10 | * 11 | * This software is licensed to you under the terms of the Cisco Sample 12 | * Code License, Version 1.1 (the "License"). You may obtain a copy of the 13 | * License at 14 | * 15 | * https://developer.cisco.com/docs/licenses 16 | * 17 | * All use of the material herein must be in accordance with the terms of 18 | * the License. All rights not expressly granted by the License are 19 | * reserved. Unless required by applicable law or agreed to separately in 20 | * writing, software distributed under the License is distributed on an "AS 21 | * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 22 | * or implied. 23 | */ 24 | 25 | import xapi from 'xapi'; 26 | 27 | // Standard position for immersive share, bottom right in half size and full opacity 28 | let immersiveVideoParams = {X: 8000, Y: 7500, Scale: 50, Opacity: 100}; 29 | let source = 'UsbC'; 30 | let immersiveMode = 'Blend'; 31 | let backgroundImage; 32 | let backgroundMode; 33 | let isImmersiveVideo = false; 34 | let positionMovement = 1000; 35 | const maxSizeOpacity = 100; 36 | const maxMovement = 2500; 37 | 38 | 39 | // Updates Source UI 40 | function updateSourceModeUI(widget, lable) { 41 | xapi.command('UserInterface Extensions Widget SetValue', { 42 | WidgetId: widget+'_immersiveVideo', 43 | Value: lable 44 | }); 45 | }; 46 | 47 | // Updates Slider UI 48 | function updateSliderUI(widget, lable) { 49 | // Update text lable 50 | xapi.command('UserInterface Extensions Widget SetValue', { 51 | WidgetId: widget+'Lable_immersiveVideo', 52 | Value: lable 53 | }); 54 | 55 | // Update Slider level 56 | let maxLevel; 57 | if (widget === 'posAdjustment') {maxLevel = maxMovement} 58 | else {maxLevel = maxSizeOpacity}; 59 | 60 | const level = Math.round(parseInt(lable) * 255 / maxLevel); 61 | xapi.command('UserInterface Extensions Widget SetValue', { 62 | WidgetId: widget+'Slider_immersiveVideo', 63 | Value: level 64 | }); 65 | }; 66 | 67 | async function getBackgroundSettings() { 68 | backgroundImage = await xapi.Status.Cameras.Background.Image.get(); 69 | backgroundMode = await xapi.Status.Cameras.Background.Mode.get(); 70 | }; 71 | 72 | function unsetGUIValue(guiId) { 73 | xapi.command('UserInterface Extensions Widget UnsetValue', { 74 | WidgetId: guiId 75 | }); 76 | } 77 | 78 | // Set immersive Video 79 | function immersiveVideo(x = immersiveVideoParams.X, y = immersiveVideoParams.Y, scale = immersiveVideoParams.Scale, opacity = immersiveVideoParams.Opacity) { 80 | isImmersiveVideo = true; 81 | immersiveVideoParams = {X: x, Y: y, Scale: scale, Opacity: opacity, Composition: immersiveMode}; 82 | xapi.command('Cameras Background Set', { Mode: source }); 83 | xapi.command('Cameras Background ForegroundParameters Set', immersiveVideoParams); 84 | }; 85 | 86 | // Unset immersive Video 87 | function disableImmersiveVideo() { 88 | isImmersiveVideo = false; 89 | if (backgroundMode === 'Image') { xapi.command('Cameras Background Set', { Image: backgroundImage, Mode: backgroundMode }); } 90 | else {xapi.command('Cameras Background Set', { Mode: backgroundMode }); }; 91 | }; 92 | 93 | xapi.on('ready', () => { 94 | updateSourceModeUI('source', source); 95 | updateSourceModeUI('immersiveMode', immersiveMode); 96 | updateSliderUI('size', immersiveVideoParams.Scale); 97 | updateSliderUI('opacity', immersiveVideoParams.Opacity); 98 | updateSliderUI('posAdjustment', positionMovement); 99 | getBackgroundSettings(); 100 | }); 101 | 102 | // Event if Background Image or Mode has been changed 103 | xapi.status.on('Cameras Background', (event) => { 104 | if (!isImmersiveVideo) { 105 | if (event['Image']) {backgroundImage = event['Image']; } 106 | else {backgroundMode = event['Mode']; }; 107 | }; 108 | }); 109 | 110 | xapi.event.on('UserInterface Extensions Widget Action', (event) => { 111 | if (event.WidgetId.includes('_immersiveVideo')) { 112 | // Event to change source for immersive Video 113 | if (event.WidgetId === 'source_immersiveVideo') { 114 | source = event.Value; 115 | } 116 | // Event to change mode for immersive Video 117 | else if(event.WidgetId === 'immersiveMode_immersiveVideo') { 118 | immersiveMode = event.Value; 119 | } 120 | // Event on Sliders to update UI and ImmersiveVideo 121 | else if (event.WidgetId.includes('Slider_immersiveVideo') && event.Type === 'changed') { 122 | let widget = event.WidgetId.replace('Slider_immersiveVideo', ''); 123 | let lable; 124 | 125 | switch (event.WidgetId) { 126 | case 'sizeSlider_immersiveVideo': 127 | lable = Math.round(event.Value * maxSizeOpacity / 255); 128 | if (lable == 0) {lable = 1}; 129 | immersiveVideoParams.Scale = lable; 130 | break; 131 | case 'opacitySlider_immersiveVideo': 132 | lable = Math.round(event.Value * maxSizeOpacity / 255); 133 | immersiveVideoParams.Opacity = lable; 134 | break; 135 | case 'posAdjustmentSlider_immersiveVideo': 136 | lable = Math.round(event.Value * maxMovement / 255 / 100) * 100; 137 | positionMovement = lable; 138 | default: 139 | // do nothing 140 | }; 141 | updateSliderUI(widget, lable); 142 | } 143 | // Preset position of immersive video 144 | else if (event.WidgetId === 'position_immersiveVideo' && event.Type === 'released') { 145 | switch (event.Value) { 146 | case 'upperLeft': 147 | immersiveVideo(1000, 2500); 148 | break; 149 | case 'upperRight': 150 | immersiveVideo(8000, 2500); 151 | break; 152 | case 'upperCenter': 153 | immersiveVideo(5000, 2500); 154 | break; 155 | case 'lowerCenter': 156 | immersiveVideo(5000, 7500); 157 | break; 158 | case 'lowerLeft': 159 | immersiveVideo(1000, 7500); 160 | break; 161 | case 'lowerRight': 162 | immersiveVideo(8000, 7500); 163 | break; 164 | case 'activate': 165 | immersiveVideo(); 166 | break; 167 | case 'reset': 168 | if (isImmersiveVideo) {immersiveVideo(8000, 7500, 50, 100);} 169 | else {immersiveVideoParams = {X: 8000, Y: 7500, Scale: 50, Opacity: 100}}; 170 | updateSliderUI('size', immersiveVideoParams.Scale); 171 | updateSliderUI('opacity', immersiveVideoParams.Opacity); 172 | updateSliderUI('posAdjustment', 1000); 173 | break; 174 | case 'deactivate': 175 | disableImmersiveVideo(); 176 | break; 177 | default: 178 | // do nothing 179 | } 180 | setTimeout(() => { unsetGUIValue(event.WidgetId); }, 200); 181 | } 182 | // Update position of immersive video 183 | else if (event.WidgetId == 'posAdjustmentPad_immersiveVideo' && event.Type == 'released') { 184 | switch (event.Value) { 185 | case 'left': 186 | if(immersiveVideoParams.X - positionMovement >= 0) {immersiveVideoParams.X -= positionMovement}; 187 | break; 188 | case 'right': 189 | if(immersiveVideoParams.X + positionMovement <= 10000) {immersiveVideoParams.X += positionMovement}; 190 | break; 191 | case 'up': 192 | if(immersiveVideoParams.Y - positionMovement >= 0) {immersiveVideoParams.Y -= positionMovement}; 193 | break; 194 | case 'down': 195 | if(immersiveVideoParams.Y + positionMovement <= 10000) {immersiveVideoParams.Y += positionMovement}; 196 | break; 197 | default: 198 | //do nothing 199 | }; 200 | }; 201 | }; 202 | if(isImmersiveVideo) {immersiveVideo()}; 203 | }); 204 | 205 | -------------------------------------------------------------------------------- /DeskPro_ImmersiveVideo/DeskPro_ImmersiveVideo.xml: -------------------------------------------------------------------------------- 1 | 2 | 1.8 3 | 4 | 2 5 | immersiveComposing 6 | local 7 | Statusbar 8 | Laptop 9 | #FFB400 10 | Immersive Composing 11 | Custom 12 | 13 | ImmersiveVideo for S1 14 | 15 | Source 16 | 17 | source_immersiveVideo 18 | GroupButton 19 | size=4;columns=2 20 | 21 | 22 | UsbC 23 | USB-C 24 | 25 | 26 | Hdmi 27 | HDMI 28 | 29 | 30 | 31 | 32 | 33 | Immersive Mode 34 | 35 | immersiveMode_immersiveVideo 36 | GroupButton 37 | size=4;columns=3 38 | 39 | 40 | Blend 41 | Blend 42 | 43 | 44 | CameraPip 45 | CameraPip 46 | 47 | 48 | VideoPip 49 | VideoPip 50 | 51 | 52 | 53 | 54 | 55 | Position 56 | 57 | position_immersiveVideo 58 | GroupButton 59 | size=4;columns=3 60 | 61 | 62 | upperLeft 63 | Upper Left 64 | 65 | 66 | upperCenter 67 | Upper Center 68 | 69 | 70 | upperRight 71 | Upper Right 72 | 73 | 74 | lowerLeft 75 | Lower Left 76 | 77 | 78 | lowerCenter 79 | Lower Center 80 | 81 | 82 | lowerRight 83 | Lower Right 84 | 85 | 86 | activate 87 | Activate 88 | 89 | 90 | reset 91 | Reset 92 | 93 | 94 | deactivate 95 | Deactivate 96 | 97 | 98 | 99 | 100 | 101 | Size 102 | 103 | sizeLable_immersiveVideo 104 | ??? 105 | Text 106 | size=1;fontSize=normal;align=center 107 | 108 | 109 | sizeSlider_immersiveVideo 110 | Slider 111 | size=3 112 | 113 | 114 | 115 | Opacity 116 | 117 | opacityLable_immersiveVideo 118 | ??? 119 | Text 120 | size=1;fontSize=normal;align=center 121 | 122 | 123 | opacitySlider_immersiveVideo 124 | Slider 125 | size=3 126 | 127 | 128 | 129 | Position Adjustment 130 | 131 | posAdjustmentPad_immersiveVideo 132 | 133 | DirectionalPad 134 | size=4 135 | 136 | 137 | 138 | Adjustment Range 139 | 140 | posAdjustmentLable_immersiveVideo 141 | ??? 142 | Text 143 | size=1;fontSize=normal;align=center 144 | 145 | 146 | posAdjustmentSlider_immersiveVideo 147 | Slider 148 | size=3 149 | 150 | 151 | immersiveVideo 152 | hideRowNames=0 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /DeskPro_ImmersiveVideo/README.md: -------------------------------------------------------------------------------- 1 | # ImmersiveVideo 2 | ### Enable flexibility in your immersive video experience on your Cisco Webex DeskPro. 3 | 4 | Choose where you want to be located in your video in any size or opacity. 5 | You can also easily switch your sources between USBC or HDMI and move yourself around your video feed. 6 | 7 | --- 8 | ### Enrich the experience with immersive settings: 9 | ![Immersive settings](https://github.com/ChrisW0lf/webex-room-customization/blob/main/DeskPro_ImmersiveComposing/images/immersiveVideo.png) 10 | --- 11 | 12 | ## Requirements 13 | 1. Cisco Webex DeskPro 14 | 2. Firmware CE9.15 or newer 15 | 4. Admin user access to endpoint 16 | 17 | ## Setup 18 | 1. Import the UI file **[DeskPro_ImmersiveVideo.xml](https://github.com/ChrisW0lf/webex-room-customization/blob/main/DeskPro_ImmersiveVideo/DeskPro_ImmersiveVideo.xml)** to the **UI Extensions Editor** of your DeskPro and **Export configuration to video system**. 19 | 2. Import the macro file **[DeskPro_ImmersiveVideo.js](https://github.com/ChrisW0lf/webex-room-customization/blob/main/DeskPro_ImmersiveVideo/DeskPro_ImmersiveVideo.js)** to the **Macro Editor** of your DeskPro and **Save to System**. 20 | 21 | ## Support&Feedback 22 | Please join this **[Webex Space](https://eurl.io/#Fvo7JcAkQ)** if you need support, have questions or to start some discussions around the macro or functionality: 23 | ![QRCodeToWebexSpace](https://github.com/ChrisW0lf/webex-room-customization/blob/main/DeskPro_ImmersiveComposing/images/webexSpaceQR.png) 24 | 25 | ## Disclaimer 26 | Those examples are only samples and are **NOT guaranteed to be bug free and production quality**. 27 | 28 | The sample macros are meant to: 29 | - Illustrate how to use the CE Macros. 30 | - Serve as an example of the step by step process of building a macro using JavaScript and integration with the Codec XAPI. 31 | 32 | The sample macros are made available to Cisco partners and customers as a convenience to help minimize the cost of Cisco Finesse customizations. Cisco does not permit the use of this library in customer deployments that do not include Cisco Video Endpoint Hardware. 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | CISCO SAMPLE CODE LICENSE 2 | Version 1.1 3 | Copyright (c) 2018 Cisco and/or its affiliates 4 | 5 | These terms govern this Cisco Systems, Inc. ("Cisco"), example or demo 6 | source code and its associated documentation (together, the "Sample 7 | Code"). By downloading, copying, modifying, compiling, or redistributing 8 | the Sample Code, you accept and agree to be bound by the following terms 9 | and conditions (the "License"). If you are accepting the License on 10 | behalf of an entity, you represent that you have the authority to do so 11 | (either you or the entity, "you"). Sample Code is not supported by Cisco 12 | TAC and is not tested for quality or performance. This is your only 13 | license to the Sample Code and all rights not expressly granted are 14 | reserved. 15 | 16 | 1. LICENSE GRANT: Subject to the terms and conditions of this License, 17 | Cisco hereby grants to you a perpetual, worldwide, non-exclusive, non- 18 | transferable, non-sublicensable, royalty-free license to copy and 19 | modify the Sample Code in source code form, and compile and 20 | redistribute the Sample Code in binary/object code or other executable 21 | forms, in whole or in part, solely for use with Cisco products and 22 | services. For interpreted languages like Java and Python, the 23 | executable form of the software may include source code and 24 | compilation is not required. 25 | 26 | 2. CONDITIONS: You shall not use the Sample Code independent of, or to 27 | replicate or compete with, a Cisco product or service. Cisco products 28 | and services are licensed under their own separate terms and you shall 29 | not use the Sample Code in any way that violates or is inconsistent 30 | with those terms (for more information, please visit: 31 | www.cisco.com/go/terms). 32 | 33 | 3. OWNERSHIP: Cisco retains sole and exclusive ownership of the Sample 34 | Code, including all intellectual property rights therein, except with 35 | respect to any third-party material that may be used in or by the 36 | Sample Code. Any such third-party material is licensed under its own 37 | separate terms (such as an open source license) and all use must be in 38 | full accordance with the applicable license. This License does not 39 | grant you permission to use any trade names, trademarks, service 40 | marks, or product names of Cisco. If you provide any feedback to Cisco 41 | regarding the Sample Code, you agree that Cisco, its partners, and its 42 | customers shall be free to use and incorporate such feedback into the 43 | Sample Code, and Cisco products and services, for any purpose, and 44 | without restriction, payment, or additional consideration of any kind. 45 | If you initiate or participate in any litigation against Cisco, its 46 | partners, or its customers (including cross-claims and counter-claims) 47 | alleging that the Sample Code and/or its use infringe any patent, 48 | copyright, or other intellectual property right, then all rights 49 | granted to you under this License shall terminate immediately without 50 | notice. 51 | 52 | 4. LIMITATION OF LIABILITY: CISCO SHALL HAVE NO LIABILITY IN CONNECTION 53 | WITH OR RELATING TO THIS LICENSE OR USE OF THE SAMPLE CODE, FOR 54 | DAMAGES OF ANY KIND, INCLUDING BUT NOT LIMITED TO DIRECT, INCIDENTAL, 55 | AND CONSEQUENTIAL DAMAGES, OR FOR ANY LOSS OF USE, DATA, INFORMATION, 56 | PROFITS, BUSINESS, OR GOODWILL, HOWEVER CAUSED, EVEN IF ADVISED OF THE 57 | POSSIBILITY OF SUCH DAMAGES. 58 | 59 | 5. DISCLAIMER OF WARRANTY: SAMPLE CODE IS INTENDED FOR EXAMPLE PURPOSES 60 | ONLY AND IS PROVIDED BY CISCO "AS IS" WITH ALL FAULTS AND WITHOUT 61 | WARRANTY OR SUPPORT OF ANY KIND. TO THE MAXIMUM EXTENT PERMITTED BY 62 | LAW, ALL EXPRESS AND IMPLIED CONDITIONS, REPRESENTATIONS, AND 63 | WARRANTIES INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OR 64 | CONDITION OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON- 65 | INFRINGEMENT, SATISFACTORY QUALITY, NON-INTERFERENCE, AND ACCURACY, 66 | ARE HEREBY EXCLUDED AND EXPRESSLY DISCLAIMED BY CISCO. CISCO DOES NOT 67 | WARRANT THAT THE SAMPLE CODE IS SUITABLE FOR PRODUCTION OR COMMERCIAL 68 | USE, WILL OPERATE PROPERLY, IS ACCURATE OR COMPLETE, OR IS WITHOUT 69 | ERROR OR DEFECT. 70 | 71 | 6. GENERAL: This License shall be governed by and interpreted in 72 | accordance with the laws of the State of California, excluding its 73 | conflict of laws provisions. You agree to comply with all applicable 74 | United States export laws, rules, and regulations. If any provision of 75 | this License is judged illegal, invalid, or otherwise unenforceable, 76 | that provision shall be severed and the rest of the License shall 77 | remain in full force and effect. No failure by Cisco to enforce any of 78 | its rights related to the Sample Code or to a breach of this License 79 | in a particular situation will act as a waiver of such rights. In the 80 | event of any inconsistencies with any other terms, this License shall 81 | take precedence. 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # webex-room-customization 2 | #### Cisco Video Endpoint Macro Repository by Christian Wolf 3 | 4 | ## Welcome! 5 | Hey there, thanks for finding my repository! 6 | 7 | Here you can find a selection of my macros for CE Room Devices. Macros are a great feature introduced in CE9.2 that allows you to customise your Room Device. They are especially powerful in combination with the In-Room Control Extensions of any Cisco Webex Touch Device. 8 | 9 | #### Macros available: 10 | 11 | | Macro | Description | 12 | | :------------------------ |:-------------| 13 | | [BeRightBack](https://github.com/ChrisW0lf/webex-room-customization/tree/main/DeskPro_BeRightBack) | Show meeting participants automatically when you're away from your Cisco Webex DeskPro 14 | | [ImmersiveComposing](https://github.com/ChrisW0lf/webex-room-customization/tree/main/DeskPro_ImmersiveComposing) | Turn your Cisco Webex DeskPro into a home video studio | 15 | | [ImmersiveVideo](https://github.com/ChrisW0lf/webex-room-customization/tree/main/DeskPro_ImmersiveVideo) | Enable flexibility in your immersive video experience on your Cisco Webex DeskPro | 16 | 17 | 18 | ## Requirements 19 | 1. Cisco Room Device (MX, SX, DX, Room, Board or Desk series). 20 | 2. Firmware CE9.2.1 or newer. Some macro using newer features require newer firmware. 21 | 3. Admin user access to endpoint. 22 | 23 | ## Getting Started 24 | Read the document [Working with Macros and In-room Controls](https://www.cisco.com/c/dam/en/us/td/docs/telepresence/endpoint/ce92/sx-mx-dx-room-kit-customization-guide-ce92.pdf) for a comprehensive introduction of In-Room Controls, Macros as well as step-by-step instructions on how to build and upload your code. 25 | 26 | ## Additional Information 27 | ##### XAPI 28 | Documentation for the XAPI can be found in the [Command References overview](https://www.cisco.com/c/en/us/support/collaboration-endpoints/telepresence-quick-set-series/products-command-reference-list.html). 29 | 30 | ## Support&Feedback 31 | Please join this **[Webex Space](https://eurl.io/#Fvo7JcAkQ)** if you need support, have questions or to start some discussions around the macro or functionality: 32 | 33 | ![QRCodeToWebexSpace](https://github.com/ChrisW0lf/webex-room-customization/blob/main/DeskPro_ImmersiveComposing/images/webexSpaceQR.png) 34 | 35 | ## Disclaimer 36 | Those examples are only samples and are **NOT guaranteed to be bug free and production quality**. 37 | 38 | The sample macros are meant to: 39 | - Illustrate how to use the CE Macros. 40 | - Serve as an example of the step by step process of building a macro using JavaScript and integration with the Codec XAPI. 41 | 42 | The sample macros are made available to Cisco partners and customers as a convenience to help minimize the cost of Cisco Finesse customizations. Cisco does not permit the use of this library in customer deployments that do not include Cisco Video Endpoint Hardware. 43 | --------------------------------------------------------------------------------