Facility Control

 View Only

QLAB commands via OSC - UDP works, but not TCP

  • 1.  QLAB commands via OSC - UDP works, but not TCP

    Posted 02-04-2022 10:09

    Hi again folks!
    Been a while since I asked a question here now, but seems I have to ask again!

    I'm currently trying to get some intergration with QLAB done with DashBoard, and yeah, simple cue triggering and such is simple.
    Now I'm trying to query QLAB to give me a response with a list of queues inside a group.
    The command is simply: /cue/{cue_number}/children

    Now in order to get a reponse, I would have to send a TCP command, however, in the documentation for QLAB:
    https://qlab.app/docs/v4/scripting/osc-dictionary-v4/
    Here they state that: "When talking to QLab via UDP, each OSC message corresponds to one UDP datagram. Replies to OSC via UDP are sent on port 53001."

    Ok, fine, so I set up a listener on port 53001 just to check it out. And sure enough, it works! PERFECT!
    So I figured, ok, I'll just use the same command for sending TCP with a callback function then!
    But no... Now I dont get any response at all. Even the simple /cue/{cue_number}/start doesnt work. Not even triggering the queue in QLAB.

    And yes, the message sent is OSC, and not UDP string. QLAB does not respond to simple UDP string messages on port 53000, it does on 53535 though, so quite easy to test the command via another button for example.

    I have included the code for my testing DashBoard below, and currently, it has the working OSC via UDP enabled.
    The OSC via TCP is disabled on line 32 in the API tag for those that want to take a look.

    <abs contexttype="opengear" dblinqport="2222" gridsize="10" keepalive="true">
    <meta>
    <params>
    <param access="1" maxlength="0" name="Host" oid="Host" type="STRING" value="192.168.42.201" widget="text"/>
    <param access="1" constraint="0.0;65535.0;0.0;65535.0;1" constrainttype="INT_STEP_RANGE" name="Port" oid="Port" precision="0" type="INT32" value="53000" widget="spinner"/>
    <param access="1" maxlength="0" name="Message" oid="Message" type="STRING" value="/cue/1/start" widget="text"/>
    <param access="1" constrainttype="INT_NULL" name="Value" oid="Value" precision="0" type="INT32" value="0" widget="default"/>
    <param access="1" maxlength="0" name="img_URL" oid="img_URL" type="STRING" value="https://www.rossvideo.com/wp-content/uploads/2018/03/Ross-Logo-Living-Live.png" widget="text"/>
    <param access="1" maxlength="0" name="vid_URL" oid="vid_URL" type="STRING" value="" widget="text"/>
    <param access="1" maxlength="0" name="listener_response" oid="listener_response" type="STRING" value="" widget="multiline-text"/>
    </params>
    <api immediate="true">function createOSCMessage(cmd) {
    var messageBuilder = ogscript.createMessageBuilder();

    var len = cmd.length+1;
    var pad = (4 - len%4)%4;
    var cmdLen = len+pad; // must be integer multiple of 4
    ogscript.debug ("length: " + len + " pad: " + pad + " = " + cmdLen);
    messageBuilder.writeString(cmd);

    // put null terminator at end of command string
    messageBuilder.writeChar(0); // null terminator

    // pad end of command string with nulls
    for (var i=0; i&lt;pad; ++i) {
    messageBuilder.writeChar(0);
    }

    //Define message as String
    //QLAB didnt like this part even though it's in the documentation for OSC appereantly...
    //messageBuilder.writeChar(',');
    //messageBuilder.writeChar('s');

    return messageBuilder.toByteArray();
    }

    function callback() {
    ogscript.debug('Run callback, though it does nothing...');
    }

    function sendOSCString(ip, port, cmd) {
    ogscript.sendUDPBytes(ip, port, createOSCMessage(cmd));
    //rosstalk.sendBytes(ip, port, createOSCMessage(cmd), callback);
    }</api>
    </meta>
    <table height="370" left="40" top="40" width="490">
    <tr>
    <label colspan="2" fill="both" insets="2,2,2,2" name="Send OSC Command" rowspan="1" style="txt-align:center;bg#dark;size:Bigger;font:bold;" weightx="1.0" weighty="1.0"/>
    </tr>
    <tr>
    <label colspan="1" fill="both" insets="2,2,2,2" name="Host: " rowspan="1" style="txt-align:east;" weighty="1.0"/>
    <param colspan="1" expand="true" fill="both" insets="2,2,2,2" oid="Host" rowspan="1" weightx="1.0" weighty="1.0"/>
    </tr>
    <tr>
    <label colspan="1" fill="both" insets="2,2,2,2" name="Port: " rowspan="1" style="txt-align:east;" weighty="1.0"/>
    <param anchor="west" colspan="1" expand="true" fill="vertical" insets="2,2,2,2" oid="Port" rowspan="1" weightx="1.0" weighty="1.0"/>
    </tr>
    <tr>
    <label colspan="1" fill="both" insets="2,2,2,2" name="OSC Command:" rowspan="1" style="txt-align:east;" weighty="1.0"/>
    <param colspan="1" expand="true" fill="both" insets="2,2,2,2" oid="Message" rowspan="1" weightx="1.0" weighty="1.0"/>
    </tr>
    <tr>
    <button buttontype="push" colspan="2" fill="both" insets="2,2,2,2" name="Send command (See API for code)" rowspan="1" weightx="1.0" weighty="1.0">
    <task tasktype="ogscript">


    /*! block id=1011,1012,1014,1013 !*/
    sendOSCString(params.getValue('Host', 0), params.getValue('Port', 0), params.getValue('Message', 0))
    /*!!
    &lt;block id="1011" type="function_sendOSCString" x="283" y="10" w="243" ip="ID:1012" port="ID:1014" cmd="ID:1013" /&gt;
    &lt;block id="1012" type="param__top&amp;amp;Host (Host)[0]" x="10" y="10" w="243" SET="" /&gt;
    &lt;block id="1014" type="param__top&amp;amp;Port (Port)[0]" x="10" y="72" w="243" SET="" /&gt;
    &lt;block id="1013" type="param__top&amp;amp;Message (Message)[0]" x="10" y="134" w="243" SET="" /&gt;
    !!*/
    /*!!&lt;checksum&gt;e80c09fbda174aa7cdb9eac4d855d6da&lt;/checksum&gt;!!*/</task>
    </button>
    </tr>
    <tr/>
    </table>
    <abs height="870" left="560" top="40" width="450">
    <listener autostart="true" bottom="820" buttontype="toggle" id="" left="0" listenport="53001" maxlength="50000" name="UDP Listener" right="0" top="0" udp="true">
    <task tasktype="ogscript">if (event.getEventType() == 1) {
    var msg = '';
    var msg = event.getBytesAsString();

    msg = msg.substring(msg.indexOf("{"));
    params.setValue('listener_response', 0, msg);
    msg = JSON.parse(msg);

    var query = msg.address.replace(/\\/g, "");

    if (query.includes("/children") &amp;&amp; (msg.status == 'ok')) {
    //DO FOLLOWING IF THE STATUS IS OK AND QUERY IS FOR CHILDREN

    var x = msg.data.length;
    for (var i = 0; i &lt; msg.data.length; i++) {
    ogscript.debug(msg.data[i].number);
    ogscript.debug(msg.data[i].listName);
    }
    }
    }</task>
    </listener>
    <button buttontype="push" height="70" left="10" name="Test listener" top="790" width="200">
    <task tasktype="ogscript">/*! block id=1017 !*/
    ogscript.sendUDPString("localhost", 53001, "TEST UDP LISTENER ON 53001");
    /*!!
    &lt;block id="1017" type="ogscript_sendudpasstring" x="285" y="219" w="318" HOST="localhost" PORT="53001" STRING="TEST UDP LISTENER ON 53001" /&gt;
    !!*/
    /*!!&lt;checksum&gt;e8290166dc65f0eb1c8a03b95a9068e7&lt;/checksum&gt;!!*/</task>
    </button>
    <param expand="true" height="730" left="0" oid="listener_response" right="0" top="50"/>
    <button bottom="10" buttontype="push" height="70" name="CLEAR" right="10" width="200">
    <task tasktype="ogscript">params.setValue('listener_response', 0, '');</task>
    </button>
    </abs>
    </abs>

    BONUS: There's also a OCS message builder function in the API there for anyone that could have use for that.
    But yeah, if anyone could tell me why the TCP commands will not work, I'd greatly appreciate it.

    My biggest clue so far is this from the QLAB documentation:
    When talking to QLab via TCP, messages are framed using the double END SLIP protocol (RFC 1055) as required by the OSC 1.1 specification."
    And I'm afraid that's beyond my current knowledge to be honest...



    ------------------------------
    Aleksander Stalsberg
    Lillehammer Icehockey Club
    ------------------------------