11-21-2017 04:25 AM - edited 03-18-2019 01:38 PM
The new Macro Framework that came with CE9.2.1 allows you to create your own small "features" that runs natively on the codec. You can also create a user interface for your features by combining the In-Room Control feature with the Macro Framework!
Please share your ideas, questions, code and anything else related to the newly released Macro Framework. Happy coding!
PS: The Macro Framework is currently not supported on the SX10 (N)
Please visit the official DEVNET page for ROOM DEVICES.
10-30-2018 02:43 PM - edited 10-30-2018 02:45 PM
I have a similar question to the above. Based on the examples, you should be able to send actual XML in the commands, but it doesn't seem to work for me. For example, I'm writing a macro to swap display roles based on content sending (a bit more advanced than the one already posted here), and I'd like to be able to send the following two commands in a single command.
xapi.config.set('Video Output Connector 1 MonitorRole', 'Second'); xapi.config.set('Video Output Connector 2 MonitorRole', 'First');
Based, on the examples, this should be able to be done via XML, in the arguement, but hasn't seemed to work for me. I'm trying the below, but the console coplains about the formatting:
xapi.config.set('Video', `<Output><Connector item=1><MonitorRole>First</MonitorRole></Connector><Connector item=2><MonitorRole>Second</MonitorRole></Connector></Output>`);
Any thoughts on this?
Additionally, does anyone know if there is a way to disable the second screen when not in use? It's quite distracting to see the same content mirrored on both displays and it would be nice to disable the 2nd screen when showing local only content.
Thanks,
Sean
10-31-2018 07:32 AM
The question above refers to more than one argument which is solved by setting the ConnectorId value as an array. In your case you need the full base config and then pass the arguments.
XML wont work like that. If a multiline command takes XML input then yes but not like your example.
If you are worried that you have many scenarios and have to write the Config command multiple times I would write something like this:
const xapi = require('xapi'); const role = {1: 'First', 2: 'Second', 3: 'Third'}; const conn = {1: '1', 2: '2', 3: '3'}; function setRoles(roleMap) { for (var [key, value] of Object.entries(roleMap)) { xapi.config.set('Video Output Connector ' + conn[key] + ' MonitorRole', role[value]); } } xapi.event.on('', event => { if (event.PresentationPreviewStarted) setRoles({2: 2, 1: 3}); else if (event.PresentationStarted) setRoles({2: 1, 1: 2}); });
Maybe a bad example but my point is that if you create a function that generates the command for you. The above dynamically expands to more roles as well, just insert more combinations.
Did I understand your question correctly?
/Magnus
11-01-2018 08:27 AM - edited 11-01-2018 08:29 AM
Thanks for the response, Magnus! Interesting you can listen for events rather than just listen to for the status changes. Is there some place we can find all of the possible events we can set up listeners for (when SSH'd to a codec, you can't tab/? out items in the xevent category)?
My original questions was more to increase the speed of the change, rather than serially issues the commands one after another to send the updates as a single command like we can do with the XML API.
Additionally, I'm assuming monitor role 3 is no video, but is a role limited to SX80s? I don't see that as an option on the SX20 or Room Kit Plus.
Here's the code I have that's working, but it's definitely not going to be as efficient as your example listening for the actual events.
const xapi = require('xapi'); function presentationMode(sending) { if (sending === true) { xapi.config.set('Video Output Connector 1 MonitorRole', 'Second'); xapi.config.set('Video Output Connector 2 MonitorRole', 'First'); } else { xapi.config.set('Video Output Connector 1 MonitorRole', 'First'); xapi.config.set('Video Output Connector 2 MonitorRole', 'Second'); } } function checkStatus(status) { console.log('status change', status); // first check if codec is sending or receiving content in a call if (status.Mode) { if (status.Mode === 'Sending' || status.Mode === 'Receiving' ) { presentationMode(true); } if (status.Mode === "Off") { presentationMode(false); } } else if (status.LocalInstance) { if (status.LocalInstance[0].SendingMode === 'LocalOnly') { presentationMode(true); } else if (status.LocalInstance[0].ghost === 'True') { presentationMode(false); } } } // Event listener for all presentation mode changes xapi.status.on('Conference Presentation', checkStatus);
Thanks,
Sean
11-06-2018 02:55 PM
For SX20 no, for SX80 yes as you already guessed, but I put that in there just as an example.
You see the base events in the xEvents command but the event can have a lot of metadata. The event.PresentationStarted has metadata for example. Here is a simple example how to capture the data for a specific event:
const xapi = require('xapi'); xapi.event.on('PresentationStarted', event => { console.log(JSON.stringify(event)); });
Produces and output of the following if presentation is started in a call:
'{"id":"1","Cause":"userRequested","ConferenceId":"6","Mode":"Sending","CallId":"1","LocalInstance":"1","LocalSource":"2"}'
This data I can use upon an event. If event.Mode == 'Sending' do whatever. Just see what data it spits out in the different events.
Its pretty much the same as registering an xFeedback in the xAPI but the macros are more practical:
xfeedback register event/presentationstarted ** end OK *e PresentationStarted Cause: userRequested *e PresentationStarted ConferenceId: 6 *e PresentationStarted Mode: Sending *e PresentationStarted CallId: 1 *e PresentationStarted LocalInstance: 1 *e PresentationStarted LocalSource: 2 ** end
xFeedback is very nice to test the events to see what it spits out without creating a macro. Its quick and easy. Then you may see that PresentationStarted has the Mode which might be the one interesting to you, you just want to listen to that event:
const xapi = require('xapi'); xapi.event.on('PresentationStarted Mode', event => { console.log(JSON.stringify(event)); });
Outputs:
'"Sending"'
11-08-2018 07:36 PM
Hi Magnus - I've got one related to this I'm hoping you or someone can assist with...
Rather than swapping around monitor roles, we want to enable/disable HDMI output 3 on an SX80 via a Macro, but haven't been able to find a way to do it.
The use case is a combined/split room scenario whereby the third screen should either be off or have no video signal when the rooms are "split". We've managed to work out the audio etc using macros but haven't found a way to disable the third HDMI output when required.
Any ideas?
11-13-2018 02:25 PM
Afaik there are no options to turn off the HDMI output connectior via the API (video) on demand. If the TV has some kind of API where you can turn it off and on I guess that could be something to consider?
/Magnus
11-13-2018 02:35 PM
Thanks Magnus, we'll look into that.
10-31-2018 07:42 AM
This can be solved using the below example:
const xapi = require('xapi'); function unsetGUIValue(guiId) { xapi.command('UserInterface Extensions Widget UnsetValue', { WidgetId: guiId }); } function compose(sources, parts) { const layout = (parts[2] === 'e') ? 'equal':'pip' xapi.command('Video Input SetMainVideoSource', { ConnectorId: sources, Layout: layout }).catch(e => { xapi.command('UserInterface Message TextLine Display', { Text: e.message, duration: 3 }); }); } xapi.event.on('UserInterface Extensions Widget Action', e => { if (e.Type == "released") { const parts = e.WidgetId.split('_'); const sourcecombo = e.Value.split('-'); compose(sourcecombo,parts); unsetGUIValue(e.WidgetId); } });
The above takes the WidgetID (which is named accordingly so it can be parsed by the code) and generates the source combo and the layout.
An example WidgetID can be:
<Widget> <WidgetId>s_2_e_3</WidgetId> <Type>GroupButton</Type> <Options>size=4</Options> <ValueSpace> <Value> <Key>3-1</Key> <Name>S3-S1</Name> </Value> <Value> <Key>3-2</Key> <Name>S3-S2</Name> </Value> <Value> <Key>3-4</Key> <Name>S3-S4</Name> </Value> </ValueSpace> </Widget>
This way I can just create more buttons in the In-Room Control editor without touching the Macro code.
/Magnus
11-07-2018 01:51 PM
Right after macros were introduced, we created one to help our users dial meetings at our custom webex url. They push a button, it pops up a dialog box asking for the 9 digit meeting ID, then the script appends @ourcustomdomain.webex.com to the end and dials it as a SIP call.
This was working just fine until CE 9.5.0 and/or Audio Console, which I noticed creates its own macro. I have had complaints from users in three different rooms so far saying that pressing the 'dial video' button doesn't pop up the dialog box anymore. I think that the only thing these rooms have in common is that the codecs are running 9.5.0 and we've probably used the audio console to configure all of them.
Panel:
<Extensions> <Version>1.4</Version> <Panel> <Icon>Language</Icon> <Type>Home</Type> <Page> <Name>Citadel WebEx Shortcut</Name> <Row> <Name>Click to Dial Citadel WebEx:</Name> <Widget> <WidgetId>dial_webex_video_number</WidgetId> <Name>Dial Video by WebEx Meeting ID</Name> <Type>Button</Type> <Options>size=4</Options> </Widget> <Widget> <WidgetId>dial_webex_audio</WidgetId> <Name>WebEx Audio Only</Name> <Type>Button</Type> <Options>size=4</Options> </Widget> </Row> <PageId>citadel_webex</PageId> <Options/> </Page> <Name>WebEx</Name> </Panel> </Extensions>
Macro:
const xapi = require('xapi'); // These match the widget ids of the In-Room control buttons const numbers = { dial_webex_video: 'meet@citadelmeetings.webex.com', dial_webex_audio: '2000', }; function dial(number) { // console.log('dial', number); xapi.command('dial', { Number: number }); } function listenToGui() { xapi.event.on('UserInterface Extensions Widget Action', (event) => { if (event.Type === 'clicked') { if (event.WidgetId === 'dial_webex_video_number') { // Show the number entry screen xapi.command(' UserInterface Message TextInput Display', {FeedbackId: 'webex_meeting_id', InputType: 'Numeric', Placeholder: '123456789', SubmitText: 'Dial Webex', Text: 'Enter your 9-digit meeting ID. This will only work for @citadelmeetings.webex.com IDs.', Title: 'Enter Citadel WebEx ID'}); } else { const number = numbers[event.WidgetId]; if (number) dial(number); else console.log('Unknown button pressed', event.WidgetId); } } }); xapi.event.on('UserInterface Message TextInput Response', (event) => { if (event.FeedbackId === 'webex_meeting_id') { const constructed_number = event.Text + '@citadelmeetings.webex.com'; // console.log('Trying to dial meeting: ', constructed_number); dial(constructed_number); } }); } listenToGui();
Your thoughts and feedback are appreciated!
11-07-2018 02:18 PM
Never mind! See https://bst.cloudapps.cisco.com/bugsearch/bug/CSCvm92418/
In the mean time I hope the script example was helpful for folks.
11-07-2018 02:20 PM
That bug was fixed in CE9.5.1, it just has not updated yet.
/Magnus
12-07-2018 11:03 AM
Hello,
We're trying to code macros with SX80. We have created a panel on the Touch10 with 2 state-less buttons, called 'renater' and 'webex'. When I press one of these buttons, I'm trying to show a message on screen.
The "event.Type === 'clicked'" is perfectly cpatured, but when it enters the "if ( event.WidgetID === 'renater') {....}", it seems that WidgetID is not captured.
Here is the code :
const xapi = require('xapi');
function showOnScreen(title, text, duration = 5) {
xapi.command('UserInterface Message Alert Display', {
Title: title,
Text: text,
Duration: duration,
});
}
function switchDefaultProtocol(event) {
if (event.Type === 'clicked') {
if (event.WidgetID === 'renavisio' ) {
const msgSIP = 'SIP';
showOnScreen('Default Call Protocol:', msgSIP);
}
if (event.WidgetID === 'webex' ) {
const msgWBX = 'WEBEX';
showOnScreen('Default Call Protocol:', msgWBX);
}
}
}
xapi.event.on('UserInterface Extensions Widget Action', switchDefaultProtocol);
What are we doing wrong ?
12-10-2018 04:37 AM
Hi
You have a typo in the WidgetID if you change this to event.WidgetId (WidgetID -> WidgetId) it should work.
/Magnus
12-10-2018 05:02 AM
12-10-2018 05:07 AM
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide