Automated Testing With Engage Scripting - rallytac/pub GitHub Wiki
Overview
As you know, Engage is a high-performance engine that provides communications capabilities for applications. When developing those applications, or when we just want to test something out on a network or interoperate with a 3rd-party system, it would be ideal to use a simple command-line application on a platform that Engage works on and which offers a terminal-style interface.
For this purpose, we created the Engage-Cmd application. This is a tool we use here at Rally Tactical Systems to exercise Engage, to test out new ideas, and so on. Engage-Cmd also serves as a reference application for developers to learn how to call the Engage APIs because its provided as C++ source code (as well as binary versions for a variety of platforms).
Now, because Engage-Cmd is a command-line application, your interaction with it is via typed commands in a terminal window (and there's tons of commands!). While this is great for quick-and-easy testing, it would be great if these commands could be automated in some fashion for purposes of frequent operations or, in the case of QA testing, repetitive operations. We have a answer for that - scripting!
A script is simply a text file containing a set of instructions that Engage-Cmd carries out. These commands are part of a very simple (and rather limited) language that Engage-Cmd supports. While the language is unsophisticated, it does have a few benefits - including simplicity and ease of understanding. Also, because the language is so incredibly simple, Engage-Cmd is kept minimal as a result and there is not any dependency on external language interpreters such as Python, Ruby, or Javascript. (We noted that Engage-Cmd is provided in source form in the RTS public Github repository so feel free to modify the code to add your own features and capabilities.)
Stuff We'll Need
Besides the actual Engage-Cmd executable, we're going to need some additional goodies to make everything work. We're going to need configurations, certificates (and keys), and (of course) a script. So let's get going...
Engine Policy
Engage has a lot of configuration options so that it can be tuned for specific use-cases, platform specific operations, and so on. While most of these options can generally be left to their defaults; there are some items that need to be provided. These are provided in a configuration known as the "Engine Policy".
To keep things simple we're going to use the smallest number of policy settings we can get away with. We really just need details about security-related items such as the default X.509 certificate that Engage will use and licensing information. (Actually ... even licensing is optional. If Engage isn't licensed, everything works as expected except that audio transmission is limited to 3 seconds at a time.)
One thing we might need to tweak, though, is which network interface to use. This is particularly important on computers with multiple network connections. This policy includes the "defaultNic
" property - which is empty. Leave it as-is or, if you need to specify a network interface, provide the operating-system defined name such as "en0
", "ens33
", "wlan0
", and so on.
Copy and paste this content into a file named "test-policy.json
".
{
"networking":{
"defaultNic":""
},
"security":{
"certificate":{
"certificate":"@./rtsFactoryDefaultEngage.pem",
"key":"@./rtsFactoryDefaultEngage.key"
}
},
"licensing":{
"entitlement": "",
"key":"",
"activationCode":"",
"manufacturerId":""
},
"timelines": {
"enabled":false
}
}
Mission Configuration
Engage-Cmd needs a mission configuration that it'll use. For this example, we're going to have a super-simple mission configuration that consists of a single audio group named "Test Group 1". We're going to want the group to function on a multicast network or in a unicast configuration using a Rallypoint. So we'll include a multicast address and port for the multicast use-case.
Also, because we might want to take a look at the traffic on the network using an analyzer such as Wireshark, we're not going to encrypt the traffic (i.e. no "cryptoPassword" attribute). Finally, we're going to want to use a simple audio CODEC that is easily understood by tools such as Wireshark. For this purpose we'll use G.711 muLaw ("encoder" of a value of 1) and framing our RTP packets in 20 millisecond blocks.
Copy and paste this content into a file named "test-mission.json
".
{
"id":"{9cc4d109-e64e-4499-8d5e-a7b4c7e19f2e}",
"name":"Test Mission",
"description":"Used to demonstrate automated testing",
"groups":[
{
"type":1,
"id":"{c568debe-dcd6-45ce-bcd0-84be0114af8f}",
"name":"Test Group 1",
"blockAdvertising":false,
"rx":{
"address":"239.42.42.1",
"port":42000
},
"tx":{
"address":"239.42.42.1",
"port":42000
},
"txAudio":{
"encoder":1,
"fdx":false,
"framingMs":20,
"maxTxSecs":0,
"noHdrExt":false
}
}
]
}
Rallypoint Information
If we're going to run in multicast mode, we don't need any additional configuration. However, if we want to use a Rallypoint then we're going to need to tell Engage about it. While this information is ultimately contained in each group's configuration in the mission, Engage-Cmd has a neat feature whereby it will merge Rallypoint information into a group's information from a mission file prior to giving it to the Engage Engine. The benefit to this is that we can switch between multicast and unicast (Rallypoint) mode for a mission simply by telling Engage-Cmd about the Rallypoint configuration file. In other words, we don't need to maintain separate mission configurations (for multicast and unicast respectively). And that's terrific because mission configurations can become quite complex and there's always a risk of our mission configurations getting out of sync if we have more than one that basically describe the same thing - except for Rallypoint information.
If we assume that our Rallypoint is at "rallypoint.example.com", our Rallypoint configuration looks as follows. Copy and paste this content into a file named "test-rp.json
" and change "rallypoint.example.com" to the IP address or DNS hostname of your Rallypoint. Note that we have turned off peer verification and allowed self-signed certificates in this example. This is done so that we can connect to Rallypoints that may not be operating in high-security mode. If your Rallypoint is operating in this mode, feel free to enable peer verification and disallow self-signed certificates.
{
"host":
{
"address":"rallypoint.example.com",
"port":7443
},
"certificate":"@./rtsFactoryDefaultEngage.pem",
"certificateKey":"@./rtsFactoryDefaultEngage.key",
"verifyPeer":false,
"allowSelfSignedCertificate":true,
"caCertificates":
[
"@./rtsCA.pem"
]
}
Security Items
One last thing before we can get going is the need for security certificates. You probably saw references to these in the policy file as well as the Rallypoint configuration. Don't worry too much about right now about how and why they're used - just trust that you need them.
Copy and paste the following into a file named "rtsCA.pem
".
-----BEGIN CERTIFICATE-----
MIIDYzCCAsUCCQCv5htRvPUEMTAKBggqhkjOPQQDAjCB9TELMAkGA1UEBhMCVVMx
EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxJTAjBgNVBAoM
HFJhbGx5IFRhY3RpY2FsIFN5c3RlbXMsIEluYy4xSDBGBgNVBAsMPyhjKSAyMDE5
IFJhbGx5IFRhY3RpY2FsIFN5c3RlbXMsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1
c2Ugb25seTEpMCcGA1UEAwwgUmFsbHkgVGFjdGljYWwgU3lzdGVtcyBSb290IENB
IDExIzAhBgkqhkiG9w0BCQEWFHN1cHBvcnRAcmFsbHl0YWMuY29tMB4XDTE5MDgy
NjIzMzk0NloXDTI5MDgyMzIzMzk0NlowgfUxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
DApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMSUwIwYDVQQKDBxSYWxseSBU
YWN0aWNhbCBTeXN0ZW1zLCBJbmMuMUgwRgYDVQQLDD8oYykgMjAxOSBSYWxseSBU
YWN0aWNhbCBTeXN0ZW1zLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkx
KTAnBgNVBAMMIFJhbGx5IFRhY3RpY2FsIFN5c3RlbXMgUm9vdCBDQSAxMSMwIQYJ
KoZIhvcNAQkBFhRzdXBwb3J0QHJhbGx5dGFjLmNvbTCBmzAQBgcqhkjOPQIBBgUr
gQQAIwOBhgAEAFq4pJf5N9/jike4V/go5seUVksUwkzkvT8EgFzVuqbJq8RgspHi
ucZNqgOPk4u5jIv2L8slsBf+4CzywG9fy2kmAK2TObjzXRdcyjP5Z68D43UvGS5X
5nGoHh+vsoNrThLlf+b5dP/Y6wdEPv5a3LBHRuJAspjg6KBTYXz24NsNzitwMAoG
CCqGSM49BAMCA4GLADCBhwJCAT+UvorzWqLn7lN5tjCjnHZWZpntWS+8Evj7Vkn6
cXhov2EmYWOTvU/l2Fx7RBR9Qndj4Aiv+FMGVgXKBlxZGP3bAkE4ZmS+yTbHMtGn
AQzDVYaZOZtZLlBvekiCqO9nyeLPwEE3yFxwj3iMLmHEQka/g3xi4AjLpdK6Pzdy
mh/JGZAhEw==
-----END CERTIFICATE-----
Copy and paste the following into a file named "rtsFactoryDefaultEngage.pem
".
-----BEGIN CERTIFICATE-----
MIIDZjCCAscCCQCty2HImU4h4TAKBggqhkjOPQQDAjCB9TELMAkGA1UEBhMCVVMx
EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxJTAjBgNVBAoM
HFJhbGx5IFRhY3RpY2FsIFN5c3RlbXMsIEluYy4xSDBGBgNVBAsMPyhjKSAyMDE5
IFJhbGx5IFRhY3RpY2FsIFN5c3RlbXMsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1
c2Ugb25seTEpMCcGA1UEAwwgUmFsbHkgVGFjdGljYWwgU3lzdGVtcyBSb290IENB
IDExIzAhBgkqhkiG9w0BCQEWFHN1cHBvcnRAcmFsbHl0YWMuY29tMB4XDTE5MDkw
NzAxNTMwNloXDTI5MDkwNDAxNTMwNlowgfcxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
DApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMSUwIwYDVQQKDBxSYWxseSBU
YWN0aWNhbCBTeXN0ZW1zLCBJbmMuMUgwRgYDVQQLDD8oYykgMjAxOSBSYWxseSBU
YWN0aWNhbCBTeXN0ZW1zLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkx
KzApBgNVBAMMIkVuZ2FnZSBGYWN0b3J5IERlZmF1bHQgQ2VydGlmaWNhdGUxIzAh
BgkqhkiG9w0BCQEWFHN1cHBvcnRAcmFsbHl0YWMuY29tMIGbMBAGByqGSM49AgEG
BSuBBAAjA4GGAAQBFaIWniVXPmTjO4IcJmbXYCoKOSbqEjavLotDznTjEe0A+SJH
a4YLbIj5xTsfgq6RWRHpzFBuvOC2ToKbR6/92jIB0bHZlHL2vN6ADQi7qSC2RJEK
JVIs1PLYfNfvNUhRvJJICPDJZ2D7xfXwxPpjLlZh+JhT6DBuGqR6QxtTRDNgpp4w
CgYIKoZIzj0EAwIDgYwAMIGIAkIBCtpJbtTuIRs7V4xOH8It78m1dv00gfHqOG0c
MrUJHXJFLlT9yBTjiqK4NQsaYQgWiSrYpGLQ1I9h6A/D1yVId78CQgFa33PUA2nW
TLabPBpdN3lno75IMHBHZ/nIPWW+KhZHzcS2pEXFT9X+KuKLpCZzos7/ZYr+tWJr
lsr93Xdm0Z9nJA==
-----END CERTIFICATE-----
Copy and paste the following into a file named "rtsFactoryDefaultEngage.key
".
-----BEGIN EC PARAMETERS-----
BgUrgQQAIw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MIHbAgEBBEGXacsoDqNimVk60h7drTtFxBZsps6o3iXqUbLhJHuE9UmCqqyrAJOD
VWcd4DDNGVSmOo1vj7+ng4mog2u71tbxJqAHBgUrgQQAI6GBiQOBhgAEARWiFp4l
Vz5k4zuCHCZm12AqCjkm6hI2ry6LQ8504xHtAPkiR2uGC2yI+cU7H4KukVkR6cxQ
brzgtk6Cm0ev/doyAdGx2ZRy9rzegA0Iu6kgtkSRCiVSLNTy2HzX7zVIUbySSAjw
yWdg+8X18MT6Yy5WYfiYU+gwbhqkekMbU0QzYKae
-----END EC PRIVATE KEY-----
The Script
Finally, the whole point of this wiki is to explain how we can automate a testing using a script, so this is a good time to actually show what the script looks like. Here's it is. It's pretty straightforward so rather than explain it in detail here, take a read through it. Note that lines that begin with "#" are comments that are ignored by Engage-Cmd.
Copy and paste this content into a file named "test-1.engagescript
".
# Engage Test Script
# Create Test Group 1 (it's group index is 0 as per the mission configuration), wait for
# up to 5000 ms for the object to be created
create 0
waitforgroup 0 created goto abort.created after 5000
# Join Test Channel 1, wait for up to 5000 ms to get our notification
join 0
waitforgroup 0 joined goto abort.joined after 5000
# Zero this out
set pttcount 0
:looptop
# Sleep between PTTs
sleep 1000
# Bump our PTT counter
add pttcount 1
# Start transmitting and wait for up to 5000 ms for our notification of txstarted. If
# this fails, just go back to the start of the loop where we sleep for a little while.
begintx 0
waitforgroup 0 txstarted goto looptop after 5000
# Log starting of PTT
message.info START TX - PTT count = ${pttcount}
# Keep transmitting for a while - 2.5 seconds (2500 milliseconds) in this case
sleep 2500
# Stop transmitting and wait for up to 5000 ms for our notification of txended. If
# this fails, just go back to the start of the loop where we sleep for a little while.
message.info END TX
endtx 0
waitforgroup 0 txended goto looptop after 5000
# Go again
goto looptop
# These just display errors and quit the script
:abort.created
message.fatal Fatal error encountered while waiting for group created!
goto done
:abort.joined
message.fatal Fatal error encountered while waiting for group joined!
goto done
:abort.connected
message.fatal Fatal error encountered while waiting for group connected!
goto done
:done
Running It In Multicast Mode
Now that we have everything in place, we can get going with our test. This is pretty straight-forward.
Make sure that you have the correct binaries for the platform you're running on - you can get these from the "bin
" folder on the RTS Github public repository, place them in the same directory as the files you saved above, and run the following:
./engage-cmd -ep:test-policy.json -mission:test-mission.json -script:test-1.engagescript
If all goes well, you should see a whole lot of activity as the script executes. To stop execution, simply press Ctrl-C.
Here's an example output of this script running on a MacBook Pro. While some output may be a little different on your machine, most of the output should be the same.
My-MacBook-Pro:tmp dev$ ./engage-cmd -ep:test-policy.json -mission:test-mission.json -script:test-1.engagescript
---------------------------------------------------------------------------------
Engage-Cmd version 1.109.8864 for darwin_x64
Copyright (c) 2019 Rally Tactical Systems, Inc.
Build time: Dec 17 2019 @ 11:04:43
darwin_x64
cpu:8
mfd:256
---------------------------------------------------------------------------------
[0]
[0]
[50]
[0]
[2500]
[0]
name='en0', friendlyName='Wi-Fi', description='IEEE80211', family=2, address='192.168.1.182', available=1, loopBack=0, supportsMulticast=1
Groups:
index=0, type=0, id={c568debe-dcd6-45ce-bcd0-84be0114af8f}, name=Test Group 1, encrypted=no, fullDuplex=no
2019:12:17 23:12:21.890 [0x11b4ba5c0- ] I/====EngageInterface====: Engage Engine version 1.109.8864 for darwin_x64 v0.0.0, build time Dec 17 2019 @ 11:03:45
2019:12:17 23:12:21.891 [0x11b4ba5c0- ] D/====EngageInterface====: engageInitialize()
2019:12:17 23:12:21.897 [0x70000f478000- apiCallQ] W/License: failed to find a suitable hardware identifier - trying the operating platform
2019:12:17 23:12:21.898 [0x70000f478000- apiCallQ] I/Engine: default security certificate:
subject..........: [/C=US/ST=Washington/L=Seattle/O=Rally Tactical Systems, Inc./OU=(c) 2019 Rally Tactical Systems, Inc. - For authorized use only/CN=Engage Factory Default Certificate/[email protected]]
issuer...........: [/C=US/ST=Washington/L=Seattle/O=Rally Tactical Systems, Inc./OU=(c) 2019 Rally Tactical Systems, Inc. - For authorized use only/CN=Rally Tactical Systems Root CA 1/[email protected]]
selfSigned.......: [0]
version..........: [1]
notBefore........: [Sep 7 01:53:06 2019 GMT]
notAfter.........: [Sep 4 01:53:06 2029 GMT]
2019:12:17 23:12:21.898 [0x70000f478000- apiCallQ] I/Engine: assigning default certificate for timeline signing
2019:12:17 23:12:21.898 [0x70000f478000- apiCallQ] I/Engine: timeline signing certificate:
subject..........: [/C=US/ST=Washington/L=Seattle/O=Rally Tactical Systems, Inc./OU=(c) 2019 Rally Tactical Systems, Inc. - For authorized use only/CN=Engage Factory Default Certificate/[email protected]]
issuer...........: [/C=US/ST=Washington/L=Seattle/O=Rally Tactical Systems, Inc./OU=(c) 2019 Rally Tactical Systems, Inc. - For authorized use only/CN=Rally Tactical Systems Root CA 1/[email protected]]
selfSigned.......: [0]
version..........: [1]
notBefore........: [Sep 7 01:53:06 2019 GMT]
notAfter.........: [Sep 4 01:53:06 2029 GMT]
2019:12:17 23:12:21.898 [0x70000f478000- apiCallQ] E/Engine: rtpJitterMinMs cannot be less than 20
2019:12:17 23:12:21.898 [0x70000f478000- apiCallQ] I/Engine: using '/var/folders/5b/dgc17xy51qq9fvmtgd74r5m80000gp/T/com.rallytac.engage/engine' as the engine root data directory
2019:12:17 23:12:21.898 [0x70000f478000- apiCallQ] D/License: unpacking license [] [] [] [CE89A682206A8D96CE25CF7EE72EC94E]
2019:12:17 23:12:21.898 [0x70000f478000- apiCallQ] E/Engine: invalid license key and/or activation code '':':''
2019:12:17 23:12:21.912 [0x11b4ba5c0- ] D/====EngageInterface====: engageStart
D/EngageMain: on_ENGAGE_ENGINE_STARTED
2019:12:17 23:12:21.912 [0x70000f57e000- engineMainQ] I/Engine: opening database ':memory:'
buildGroupCreationJson: {"alias":"APL-00003C1E53A6","audio":{"inputGain":0,"inputId":0,"outputId":0,"outputLevelLeft":100,"outputLevelRight":100},"blockAdvertising":false,"cryptoPassword":"","id":"{c568debe-dcd6-45ce-bcd0-84be0114af8f}","interfaceName":"","name":"Test Group 1","presence":{"forceOnAudioTransmit":false,"format":0,"intervalSecs":30,"listenOnly":false},"rallypoints":[],"rx":{"address":"239.42.42.1","port":42000},"source":"","timeline":{"enabled":true,"maxAudioTimeMs":30000,"recordAudio":true},"tx":{"address":"239.42.42.1","port":42000},"txAudio":{"debug":false,"encoder":1,"extensionSendInterval":10,"fdx":false,"framingMs":20,"initialHeaderBurst":5,"maxTxSecs":0,"noHdrExt":false,"trailingHeaderBurst":5,"userTxFlags":0,"userTxPriority":0},"txOptions":{"priority":4,"ttl":128},"type":1}
2019:12:17 23:12:21.912 [0x11b4ba5c0- ] D/====EngageInterface====: engageCreateGroup(-cfg-)
2019:12:17 23:12:21.913 [0x70000f57e000- engineMainQ] I/Engine: intialized database in 1399316.000000 nanoseconds (1.399316 milliseconds)
2019:12:17 23:12:21.913 [0x70000f57e000- engineMainQ] I/Engine: timeline recording has been disabled
2019:12:17 23:12:21.913 [0x70000f57e000- engineMainQ] W/Engine: discovery has been disabled
2019:12:17 23:12:21.913 [0x70000f57e000- engineMainQ] D/License: unpacking license [] [] [] [CE89A682206A8D96CE25CF7EE72EC94E]
2019:12:17 23:12:21.913 [0x70000f57e000- engineMainQ] E/Engine: invalid license key and/or activation code '':':''
2019:12:17 23:12:21.913 [0x70000f57e000- engineMainQ] D/MyLicenseNotifications: onLicenseExpired
D/EngageMain: on_ENGAGE_LICENSE_EXPIRED
2019:12:17 23:12:21.913 [0x70000f478000- apiCallQ] D/Engine: engine started
2019:12:17 23:12:21.913 [0x70000f707000- watchdog] D/Engine: starting watchdog
2019:12:17 23:12:21.914 [0x70000f57e000- engineMainQ] D/G711Encoder: {0x7fe63e710c80} created ulaw encoder
2019:12:17 23:12:21.914 [0x70000f57e000- engineMainQ] I/Engine: {0x7fe63e803200} createSpeaker defaulting to device id 2
2019:12:17 23:12:21.914 [0x70000f57e000- engineMainQ] D/Engine: {0x7fe63e803200} createSpeaker using device id 2, h/w="AppleHDAEngineOutput:1F,3,0,1,1:0"
2019:12:17 23:12:21.914 [0x70000f57e000- engineMainQ] W/Group: configure: timeline recording enabled but no timeline object available (likely disabled in engine policy)
2019:12:17 23:12:21.914 [0x70000f57e000- engineMainQ] D/Engine: createGroup/created group '{c568debe-dcd6-45ce-bcd0-84be0114af8f}'
2019:12:17 23:12:21.914 [0x70000f57e000- engineMainQ] D/MyGroupNotifications: onGroupCreated '{c568debe-dcd6-45ce-bcd0-84be0114af8f}'
D/EngageMain: on_ENGAGE_GROUP_CREATED: {c568debe-dcd6-45ce-bcd0-84be0114af8f}
2019:12:17 23:12:21.914 [0x11b4ba5c0- ] D/====EngageInterface====: engageJoinGroup({c568debe-dcd6-45ce-bcd0-84be0114af8f})
2019:12:17 23:12:21.915 [0x70000f57e000- engineMainQ] D/Engine: joinGroup/joining group '{c568debe-dcd6-45ce-bcd0-84be0114af8f}'
2019:12:17 23:12:21.915 [0x70000f57e000- engineMainQ] D/udp.GRP:{c568debe-dcd6-45ce-bcd0-84be0114af8f}: starting rx=239.42.42.1:42000, tx=239.42.42.1:42000
2019:12:17 23:12:21.915 [0x70000f78a000- udp.GRP:{c568de] D/udp.GRP:{c568debe-dcd6-45ce-bcd0-84be0114af8f}: {0x7fe641000000} starting
2019:12:17 23:12:21.915 [0x70000f78a000- udp.GRP:{c568de] D/udp.GRP:{c568debe-dcd6-45ce-bcd0-84be0114af8f}: {0x7fe641000000} trying connection
2019:12:17 23:12:21.915 [0x70000f57e000- engineMainQ] D/Engine: {0x7fe63e803200} advertiseGroup {c568debe-dcd6-45ce-bcd0-84be0114af8f}
2019:12:17 23:12:21.915 [0x70000f78a000- udp.GRP:{c568de] D/udp.GRP:{c568debe-dcd6-45ce-bcd0-84be0114af8f}: {0x7fe641000000} [SO_NET_SERVICE_TYPE] setting networking priority type to 4, rc=0
2019:12:17 23:12:21.915 [0x70000f57e000- engineMainQ] D/DiscoveryManager: {0x7fe63e403640} advertiseGroup {c568debe-dcd6-45ce-bcd0-84be0114af8f}
2019:12:17 23:12:21.915 [0x70000f57e000- engineMainQ] D/DiscoveryManager: {0x7fe63e403640} advertiseGroup adding {c568debe-dcd6-45ce-bcd0-84be0114af8f}
2019:12:17 23:12:21.915 [0x70000f57e000- engineMainQ] D/MyGroupNotifications: onGroupJoined '{c568debe-dcd6-45ce-bcd0-84be0114af8f}'
D/EngageMain: on_ENGAGE_GROUP_JOINED: {c568debe-dcd6-45ce-bcd0-84be0114af8f}
2019:12:17 23:12:21.919 [0x70000f78a000- udp.GRP:{c568de] I/udp.GRP:{c568debe-dcd6-45ce-bcd0-84be0114af8f}: {0x7fe641000000} connected RX 239.42.42.1:42000 TX 239.42.42.1:42000 - selectSecs set to 7 seconds based on multicast rejoin
2019:12:17 23:12:21.919 [0x70000f78a000- udp.GRP:{c568de] D/Group: {0x7fe63e803e00} packet receiver is connected
2019:12:17 23:12:21.919 [0x70000f57e000- engineMainQ] D/MyGroupNotifications: onGroupConnected '{c568debe-dcd6-45ce-bcd0-84be0114af8f}'
2019:12:17 23:12:21.919 [0x70000f80d000- ] D/udp.GRP:{c568debe-dcd6-45ce-bcd0-84be0114af8f}: {0x7fe641000000} starting sender
D/EngageMain: on_ENGAGE_GROUP_CONNECTED: {c568debe-dcd6-45ce-bcd0-84be0114af8f}
2019:12:17 23:12:21.970 [0x11b4ba5c0- ] I/Script: START TX - PTT count = 1
2019:12:17 23:12:21.970 [0x11b4ba5c0- ] D/====EngageInterface====: engageBeginGroupTxAdvanced({c568debe-dcd6-45ce-bcd0-84be0114af8f}, {"alias":"[email protected]","flags":0,"includeNodeId":true,"priority":0,"subchannelTag":0})
2019:12:17 23:12:21.970 [0x70000f57e000- engineMainQ] D/Engine: beginGroupTxAdvanced/starting tx on group '{c568debe-dcd6-45ce-bcd0-84be0114af8f}'
2019:12:17 23:12:21.970 [0x70000f57e000- engineMainQ] D/Engine: {0x7fe63e803200} subscribeToMicrophone creating a microphone on device 0
2019:12:17 23:12:21.970 [0x70000f57e000- engineMainQ] I/Engine: {0x7fe63e803200} createMicrophone defaulting to device id 1
2019:12:17 23:12:21.970 [0x70000f57e000- engineMainQ] D/Engine: {0x7fe63e803200} createMicrophone using device id 1, h/w="AppleHDAEngineInput:1F,3,0,1,0:1"
2019:12:17 23:12:21.970 [0x70000f57e000- engineMainQ] D/Engine: {0x7fe63e803200} subscribeToMicrophone using the microphone on device 0 with an instance id of 0
2019:12:17 23:12:21.970 [0x70000f57e000- engineMainQ] D/Group: beginning transmission with a header size of 40 bytes, seq=42037, ts=2547748174
2019:12:17 23:12:21.970 [0x70000f57e000- engineMainQ] D/MyGroupNotifications: onGroupTxStarted '{c568debe-dcd6-45ce-bcd0-84be0114af8f}'
D/EngageMain: on_ENGAGE_GROUP_TX_STARTED: {c568debe-dcd6-45ce-bcd0-84be0114af8f}
2019:12:17 23:12:22.619 [0x70000f890000- osxMicrophone] D/OSXMicrophone: opened microphone rate=16000, channels=1, bufferms=60
2019:12:17 23:12:24.476 [0x11b4ba5c0- ] I/Script: END TX
2019:12:17 23:12:24.476 [0x11b4ba5c0- ] D/====EngageInterface====: engageEndGroupTx({c568debe-dcd6-45ce-bcd0-84be0114af8f})
2019:12:17 23:12:24.476 [0x70000f57e000- engineMainQ] D/Engine: endGroupTx/ending tx on group '{c568debe-dcd6-45ce-bcd0-84be0114af8f}'
2019:12:17 23:12:24.476 [0x70000f57e000- engineMainQ] D/Engine: {0x7fe63e803200} unsubscribeFromMicrophone releasing count of instance ID 0 on device 0
2019:12:17 23:12:24.476 [0x70000f57e000- engineMainQ] D/Engine: {0x7fe63e803200} unsubscribeFromMicrophone destroying instance ID 0 on device 0
2019:12:17 23:12:24.556 [0x70000f57e000- engineMainQ] D/MyGroupNotifications: onGroupTxEnded '{c568debe-dcd6-45ce-bcd0-84be0114af8f}'
D/EngageMain: on_ENGAGE_GROUP_TX_ENDED: {c568debe-dcd6-45ce-bcd0-84be0114af8f}
2019:12:17 23:12:24.607 [0x11b4ba5c0- ] I/Script: START TX - PTT count = 2
2019:12:17 23:12:24.607 [0x11b4ba5c0- ] D/====EngageInterface====: engageBeginGroupTxAdvanced({c568debe-dcd6-45ce-bcd0-84be0114af8f}, {"alias":"[email protected]","flags":0,"includeNodeId":true,"priority":0,"subchannelTag":0})
2019:12:17 23:12:24.608 [0x70000f57e000- engineMainQ] D/Engine: beginGroupTxAdvanced/starting tx on group '{c568debe-dcd6-45ce-bcd0-84be0114af8f}'
2019:12:17 23:12:24.608 [0x70000f57e000- engineMainQ] D/Engine: {0x7fe63e803200} subscribeToMicrophone creating a microphone on device 0
2019:12:17 23:12:24.608 [0x70000f57e000- engineMainQ] I/Engine: {0x7fe63e803200} createMicrophone defaulting to device id 1
2019:12:17 23:12:24.608 [0x70000f57e000- engineMainQ] D/Engine: {0x7fe63e803200} createMicrophone using device id 1, h/w="AppleHDAEngineInput:1F,3,0,1,0:1"
2019:12:17 23:12:24.608 [0x70000f57e000- engineMainQ] D/Engine: {0x7fe63e803200} subscribeToMicrophone using the microphone on device 0 with an instance id of 0
2019:12:17 23:12:24.608 [0x70000f57e000- engineMainQ] D/Group: beginning transmission with a header size of 40 bytes, seq=42127, ts=2547746733
2019:12:17 23:12:24.608 [0x70000f57e000- engineMainQ] D/MyGroupNotifications: onGroupTxStarted '{c568debe-dcd6-45ce-bcd0-84be0114af8f}'
D/EngageMain: on_ENGAGE_GROUP_TX_STARTED: {c568debe-dcd6-45ce-bcd0-84be0114af8f}
2019:12:17 23:12:24.636 [0x70000f890000- osxMicrophone] D/OSXMicrophone: opened microphone rate=16000, channels=1, bufferms=60
^C
My-MacBook-Pro:tmp dev$
Running It In Unicast Mode
Hopefully everything worked great for you. Now, if you want to connect through a Rallypoint instead of multicast, just add the Rallypoint configuration file to the command-line as follows:
./engage-cmd -ep:test-policy.json -mission:test-mission.json -rp:test-rp.json -script:test-1.engagescript
Here's the sample from that MacBook Pro as an example. You'll notice some errors reported about not being able to connect to "rallypoint.example.com". That's because the "test-rp.json
" file is not pointed to a valid Rallypoint host name. You should not see this if you've entered all the info needed correctly.
My-MacBook-Pro:tmp dev$ ./engage-cmd -ep:test-policy.json -mission:test-mission.json -rp:test-rp.json -script:test-1.engagescript
---------------------------------------------------------------------------------
Engage-Cmd version 1.109.8864 for darwin_x64
Copyright (c) 2019 Rally Tactical Systems, Inc.
Build time: Dec 17 2019 @ 11:04:43
darwin_x64
cpu:8
mfd:256
---------------------------------------------------------------------------------
[0]
[0]
[50]
[0]
[2500]
[0]
name='en0', friendlyName='Wi-Fi', description='IEEE80211', family=2, address='192.168.1.182', available=1, loopBack=0, supportsMulticast=1
Groups:
index=0, type=0, id={c568debe-dcd6-45ce-bcd0-84be0114af8f}, name=Test Group 1, encrypted=no, fullDuplex=no
2019:12:17 23:17:33.127 [0x116ee65c0- ] I/====EngageInterface====: Engage Engine version 1.109.8864 for darwin_x64 v0.0.0, build time Dec 17 2019 @ 11:03:45
2019:12:17 23:17:33.128 [0x116ee65c0- ] D/====EngageInterface====: engageInitialize()
2019:12:17 23:17:33.134 [0x700001c4f000- apiCallQ] W/License: failed to find a suitable hardware identifier - trying the operating platform
2019:12:17 23:17:33.135 [0x700001c4f000- apiCallQ] I/Engine: default security certificate:
subject..........: [/C=US/ST=Washington/L=Seattle/O=Rally Tactical Systems, Inc./OU=(c) 2019 Rally Tactical Systems, Inc. - For authorized use only/CN=Engage Factory Default Certificate/[email protected]]
issuer...........: [/C=US/ST=Washington/L=Seattle/O=Rally Tactical Systems, Inc./OU=(c) 2019 Rally Tactical Systems, Inc. - For authorized use only/CN=Rally Tactical Systems Root CA 1/[email protected]]
selfSigned.......: [0]
version..........: [1]
notBefore........: [Sep 7 01:53:06 2019 GMT]
notAfter.........: [Sep 4 01:53:06 2029 GMT]
2019:12:17 23:17:33.135 [0x700001c4f000- apiCallQ] I/Engine: assigning default certificate for timeline signing
2019:12:17 23:17:33.135 [0x700001c4f000- apiCallQ] I/Engine: timeline signing certificate:
subject..........: [/C=US/ST=Washington/L=Seattle/O=Rally Tactical Systems, Inc./OU=(c) 2019 Rally Tactical Systems, Inc. - For authorized use only/CN=Engage Factory Default Certificate/[email protected]]
issuer...........: [/C=US/ST=Washington/L=Seattle/O=Rally Tactical Systems, Inc./OU=(c) 2019 Rally Tactical Systems, Inc. - For authorized use only/CN=Rally Tactical Systems Root CA 1/[email protected]]
selfSigned.......: [0]
version..........: [1]
notBefore........: [Sep 7 01:53:06 2019 GMT]
notAfter.........: [Sep 4 01:53:06 2029 GMT]
2019:12:17 23:17:33.135 [0x700001c4f000- apiCallQ] E/Engine: rtpJitterMinMs cannot be less than 20
2019:12:17 23:17:33.135 [0x700001c4f000- apiCallQ] I/Engine: using '/var/folders/5b/dgc17xy51qq9fvmtgd74r5m80000gp/T/com.rallytac.engage/engine' as the engine root data directory
2019:12:17 23:17:33.135 [0x700001c4f000- apiCallQ] D/License: unpacking license [] [] [] [CE89A682206A8D96CE25CF7EE72EC94E]
2019:12:17 23:17:33.135 [0x700001c4f000- apiCallQ] E/Engine: invalid license key and/or activation code '':':''
2019:12:17 23:17:33.149 [0x116ee65c0- ] D/====EngageInterface====: engageStart
D/EngageMain: on_ENGAGE_ENGINE_STARTED
2019:12:17 23:17:33.149 [0x700001d55000- engineMainQ] I/Engine: opening database ':memory:'
buildGroupCreationJson: {"alias":"APL-00003C6E572E","audio":{"inputGain":0,"inputId":0,"outputId":0,"outputLevelLeft":100,"outputLevelRight":100},"blockAdvertising":false,"cryptoPassword":"","id":"{c568debe-dcd6-45ce-bcd0-84be0114af8f}","interfaceName":"","name":"Test Group 1","presence":{"forceOnAudioTransmit":false,"format":0,"intervalSecs":30,"listenOnly":false},"rallypoints":[{"allowSelfSignedCertificate":true,"caCertificates":["@./rtsCA.pem"],"certificate":"-----BEGIN CERTIFICATE-----\nMIIDZjCCAscCCQCty2HImU4h4TAKBggqhkjOPQQDAjCB9TELMAkGA1UEBhMCVVMx\nEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxJTAjBgNVBAoM\nHFJhbGx5IFRhY3RpY2FsIFN5c3RlbXMsIEluYy4xSDBGBgNVBAsMPyhjKSAyMDE5\nIFJhbGx5IFRhY3RpY2FsIFN5c3RlbXMsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1\nc2Ugb25seTEpMCcGA1UEAwwgUmFsbHkgVGFjdGljYWwgU3lzdGVtcyBSb290IENB\nIDExIzAhBgkqhkiG9w0BCQEWFHN1cHBvcnRAcmFsbHl0YWMuY29tMB4XDTE5MDkw\nNzAxNTMwNloXDTI5MDkwNDAxNTMwNlowgfcxCzAJBgNVBAYTAlVTMRMwEQYDVQQI\nDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMSUwIwYDVQQKDBxSYWxseSBU\nYWN0aWNhbCBTeXN0ZW1zLCBJbmMuMUgwRgYDVQQLDD8oYykgMjAxOSBSYWxseSBU\nYWN0aWNhbCBTeXN0ZW1zLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkx\nKzApBgNVBAMMIkVuZ2FnZSBGYWN0b3J5IERlZmF1bHQgQ2VydGlmaWNhdGUxIzAh\nBgkqhkiG9w0BCQEWFHN1cHBvcnRAcmFsbHl0YWMuY29tMIGbMBAGByqGSM49AgEG\nBSuBBAAjA4GGAAQBFaIWniVXPmTjO4IcJmbXYCoKOSbqEjavLotDznTjEe0A+SJH\na4YLbIj5xTsfgq6RWRHpzFBuvOC2ToKbR6/92jIB0bHZlHL2vN6ADQi7qSC2RJEK\nJVIs1PLYfNfvNUhRvJJICPDJZ2D7xfXwxPpjLlZh+JhT6DBuGqR6QxtTRDNgpp4w\nCgYIKoZIzj0EAwIDgYwAMIGIAkIBCtpJbtTuIRs7V4xOH8It78m1dv00gfHqOG0c\nMrUJHXJFLlT9yBTjiqK4NQsaYQgWiSrYpGLQ1I9h6A/D1yVId78CQgFa33PUA2nW\nTLabPBpdN3lno75IMHBHZ/nIPWW+KhZHzcS2pEXFT9X+KuKLpCZzos7/ZYr+tWJr\nlsr93Xdm0Z9nJA==\n-----END CERTIFICATE-----\n","certificateKey":"-----BEGIN EC PARAMETERS-----\nBgUrgQQAIw==\n-----END EC PARAMETERS-----\n-----BEGIN EC PRIVATE KEY-----\nMIHbAgEBBEGXacsoDqNimVk60h7drTtFxBZsps6o3iXqUbLhJHuE9UmCqqyrAJOD\nVWcd4DDNGVSmOo1vj7+ng4mog2u71tbxJqAHBgUrgQQAI6GBiQOBhgAEARWiFp4l\nVz5k4zuCHCZm12AqCjkm6hI2ry6LQ8504xHtAPkiR2uGC2yI+cU7H4KukVkR6cxQ\nbrzgtk6Cm0ev/doyAdGx2ZRy9rzegA0Iu6kgtkSRCiVSLNTy2HzX7zVIUbySSAjw\nyWdg+8X18MT6Yy5WYfiYU+gwbhqkekMbU0QzYKae\n-----END EC PRIVATE KEY-----\n","host":{"address":"rallypoint.example.com","port":7443},"transactionTimeoutMs":5000,"verifyPeer":false}],"rx":{"address":"239.42.42.1","port":42000},"source":"","timeline":{"enabled":true,"maxAudioTimeMs":30000,"recordAudio":true},"tx":{"address":"239.42.42.1","port":42000},"txAudio":{"debug":false,"encoder":1,"extensionSendInterval":10,"fdx":false,"framingMs":20,"initialHeaderBurst":5,"maxTxSecs":0,"noHdrExt":false,"trailingHeaderBurst":5,"userTxFlags":0,"userTxPriority":0},"txOptions":{"priority":4,"ttl":128},"type":1}
2019:12:17 23:17:33.149 [0x116ee65c0- ] D/====EngageInterface====: engageCreateGroup(-cfg-)
2019:12:17 23:17:33.150 [0x700001d55000- engineMainQ] I/Engine: intialized database in 1308162.000000 nanoseconds (1.308162 milliseconds)
2019:12:17 23:17:33.150 [0x700001d55000- engineMainQ] I/Engine: timeline recording has been disabled
2019:12:17 23:17:33.150 [0x700001d55000- engineMainQ] W/Engine: discovery has been disabled
2019:12:17 23:17:33.150 [0x700001d55000- engineMainQ] D/License: unpacking license [] [] [] [CE89A682206A8D96CE25CF7EE72EC94E]
2019:12:17 23:17:33.150 [0x700001d55000- engineMainQ] E/Engine: invalid license key and/or activation code '':':''
2019:12:17 23:17:33.150 [0x700001d55000- engineMainQ] D/MyLicenseNotifications: onLicenseExpired
D/EngageMain: on_ENGAGE_LICENSE_EXPIRED
2019:12:17 23:17:33.150 [0x700001c4f000- apiCallQ] D/Engine: engine started
2019:12:17 23:17:33.150 [0x700001ede000- watchdog] D/Engine: starting watchdog
2019:12:17 23:17:33.151 [0x700001d55000- engineMainQ] D/G711Encoder: {0x7fdd6ad0fca0} created ulaw encoder
2019:12:17 23:17:33.151 [0x700001d55000- engineMainQ] I/Engine: {0x7fdd6d001800} createSpeaker defaulting to device id 2
2019:12:17 23:17:33.151 [0x700001d55000- engineMainQ] D/Engine: {0x7fdd6d001800} createSpeaker using device id 2, h/w="AppleHDAEngineOutput:1F,3,0,1,1:0"
2019:12:17 23:17:33.151 [0x700001d55000- engineMainQ] W/Group: configure: timeline recording enabled but no timeline object available (likely disabled in engine policy)
2019:12:17 23:17:33.151 [0x700001d55000- engineMainQ] D/Engine: createGroup/creating unicast leaf to 'rallypoint.example.com'
2019:12:17 23:17:33.151 [0x700001d55000- engineMainQ] D/Leaf: leaf certificate:
subject..........: [/C=US/ST=Washington/L=Seattle/O=Rally Tactical Systems, Inc./OU=(c) 2019 Rally Tactical Systems, Inc. - For authorized use only/CN=Engage Factory Default Certificate/[email protected]]
issuer...........: [/C=US/ST=Washington/L=Seattle/O=Rally Tactical Systems, Inc./OU=(c) 2019 Rally Tactical Systems, Inc. - For authorized use only/CN=Rally Tactical Systems Root CA 1/[email protected]]
selfSigned.......: [0]
version..........: [1]
notBefore........: [Sep 7 01:53:06 2019 GMT]
notAfter.........: [Sep 4 01:53:06 2029 GMT]
2019:12:17 23:17:33.151 [0x700001d55000- engineMainQ] D/Engine: createGroup/created group '{c568debe-dcd6-45ce-bcd0-84be0114af8f}'
2019:12:17 23:17:33.151 [0x700001d55000- engineMainQ] D/MyGroupNotifications: onGroupCreated '{c568debe-dcd6-45ce-bcd0-84be0114af8f}'
D/EngageMain: on_ENGAGE_GROUP_CREATED: {c568debe-dcd6-45ce-bcd0-84be0114af8f}
2019:12:17 23:17:33.152 [0x116ee65c0- ] D/====EngageInterface====: engageJoinGroup({c568debe-dcd6-45ce-bcd0-84be0114af8f})
2019:12:17 23:17:33.152 [0x700001d55000- engineMainQ] D/Engine: joinGroup/joining group '{c568debe-dcd6-45ce-bcd0-84be0114af8f}'
2019:12:17 23:17:33.152 [0x700001f61000- leafQ] D/Leaf: {0x7fdd6b825400} starting
2019:12:17 23:17:33.152 [0x700001f61000- leafQ] F/Leaf: peer verification has been disabled - this is a major security threat!
2019:12:17 23:17:33.152 [0x700001fe4000- leafReader] D/Leaf: {0x7fdd6b825400} trying connection to 'rallypoint.example.com'
2019:12:17 23:17:33.152 [0x700002067000- leafRegMonitor] D/Leaf: {0x7fdd6b825400} registration monitor started
2019:12:17 23:17:33.152 [0x700001d55000- engineMainQ] D/MyGroupNotifications: onGroupJoined '{c568debe-dcd6-45ce-bcd0-84be0114af8f}'
2019:12:17 23:17:33.152 [0x700001fe4000- leafReader] D/Engine: {0x7fdd6d001800} onLeafConnecting 0x7fdd6b825400
D/EngageMain: on_ENGAGE_GROUP_JOINED: {c568debe-dcd6-45ce-bcd0-84be0114af8f}
2019:12:17 23:17:33.152 [0x700001d55000- engineMainQ] D/MyRallypointNotifications: onRpLeafConnecting 'rallypoint.example.com'
D/EngageMain: on_ENGAGE_RP_CONNECTING: rallypoint.example.com
2019:12:17 23:17:33.153 [0x700001fe4000- leafReader] E/Leaf: {0x7fdd6b825400} getaddrinfo('rallypoint.example.com') failed, errno=0
2019:12:17 23:17:33.153 [0x700001fe4000- leafReader] D/Leaf: {0x7fdd6b825400} pause for 268 before connection
2019:12:17 23:17:33.153 [0x700001fe4000- leafReader] D/Engine: {0x7fdd6d001800} onLeafPausingConnectionAttempt 0x7fdd6b825400
2019:12:17 23:17:33.153 [0x700001d55000- engineMainQ] D/MyRallypointNotifications: onRpLeafPausingConnectionAttempt 'rallypoint.example.com'
D/EngageMain: on_ENGAGE_RP_PAUSING_CONNECTION_ATTEMPT: rallypoint.example.com
2019:12:17 23:17:33.459 [0x700001fe4000- leafReader] D/Leaf: {0x7fdd6b825400} trying connection to 'rallypoint.example.com'
2019:12:17 23:17:33.459 [0x700001fe4000- leafReader] D/Engine: {0x7fdd6d001800} onLeafConnecting 0x7fdd6b825400
2019:12:17 23:17:33.459 [0x700001d55000- engineMainQ] D/MyRallypointNotifications: onRpLeafConnecting 'rallypoint.example.com'
D/EngageMain: on_ENGAGE_RP_CONNECTING: rallypoint.example.com
2019:12:17 23:17:33.460 [0x700001fe4000- leafReader] E/Leaf: {0x7fdd6b825400} getaddrinfo('rallypoint.example.com') failed, errno=0
2019:12:17 23:17:33.460 [0x700001fe4000- leafReader] D/Leaf: {0x7fdd6b825400} pause for 557 before connection
2019:12:17 23:17:33.460 [0x700001fe4000- leafReader] D/Engine: {0x7fdd6d001800} onLeafPausingConnectionAttempt 0x7fdd6b825400
2019:12:17 23:17:33.460 [0x700001d55000- engineMainQ] D/MyRallypointNotifications: onRpLeafPausingConnectionAttempt 'rallypoint.example.com'
D/EngageMain: on_ENGAGE_RP_PAUSING_CONNECTION_ATTEMPT: rallypoint.example.com
2019:12:17 23:17:34.079 [0x700001fe4000- leafReader] D/Leaf: {0x7fdd6b825400} trying connection to 'rallypoint.example.com'
2019:12:17 23:17:34.079 [0x700001fe4000- leafReader] D/Engine: {0x7fdd6d001800} onLeafConnecting 0x7fdd6b825400
2019:12:17 23:17:34.079 [0x700001d55000- engineMainQ] D/MyRallypointNotifications: onRpLeafConnecting 'rallypoint.example.com'
D/EngageMain: on_ENGAGE_RP_CONNECTING: rallypoint.example.com
2019:12:17 23:17:34.080 [0x700001fe4000- leafReader] E/Leaf: {0x7fdd6b825400} getaddrinfo('rallypoint.example.com') failed, errno=0
2019:12:17 23:17:34.080 [0x700001fe4000- leafReader] D/Leaf: {0x7fdd6b825400} pause for 1473 before connection
2019:12:17 23:17:34.080 [0x700001fe4000- leafReader] D/Engine: {0x7fdd6d001800} onLeafPausingConnectionAttempt 0x7fdd6b825400
2019:12:17 23:17:34.080 [0x700001d55000- engineMainQ] D/MyRallypointNotifications: onRpLeafPausingConnectionAttempt 'rallypoint.example.com'
D/EngageMain: on_ENGAGE_RP_PAUSING_CONNECTION_ATTEMPT: rallypoint.example.com
2019:12:17 23:17:34.151 [0x700001d55000- engineMainQ] D/Engine: housekeeper sending leaf roundtrip request to 'rallypoint.example.com'
2019:12:17 23:17:34.151 [0x700001d55000- engineMainQ] D/Leaf: {0x7fdd6b825400} sending roundtrip request ts=499145891
^C
My-MacBook-Pro:tmp dev$
Reducing Logging Output
Here at Rally Tactical we like our software to tell us what it's doing. So the logging output our code produces is quite substantial (as you can see from the example above). While this is all terrific for us RTS folks, you might not be too terribly interested in seeing all this stuff scroll by. So, you can change the logging level simply by setting an environment variable named "ENGAGE_LOG_LEVEL
". This level is defined as 0 (Fatal Errors), 1 (Errors), 2 (Warnings), 3 (Information) and, 4 (Debugging). The default is 4 (Debugging). If you only want to see warnings, errors, and fatal errors, set the level to 2. To see informational output (and skip all the debugging stuff), set the level to 3.
For example if we want to see informational, warnings, errors, and fatal errors only (i.e. no debugging):
My-MacBook-Pro:tmp dev$ export ENGAGE_LOG_LEVEL=3
If we now run our multicast configuration, theres a whole lot less stuff scrolling by.
My-MacBook-Pro:tmp dev$ ./engage-cmd -ep:test-policy.json -mission:test-mission.json -script:test-1.engagescript
---------------------------------------------------------------------------------
Engage-Cmd version 1.109.8864 for darwin_x64
Copyright (c) 2019 Rally Tactical Systems, Inc.
Build time: Dec 17 2019 @ 11:04:43
darwin_x64
cpu:8
mfd:256
---------------------------------------------------------------------------------
[0]
[0]
[50]
[0]
[2500]
[0]
name='en0', friendlyName='Wi-Fi', description='IEEE80211', family=2, address='192.168.1.182', available=1, loopBack=0, supportsMulticast=1
Groups:
index=0, type=0, id={c568debe-dcd6-45ce-bcd0-84be0114af8f}, name=Test Group 1, encrypted=no, fullDuplex=no
2019:12:17 23:27:17.498 [0x109e4e5c0- ] I/====EngageInterface====: Engage Engine version 1.109.8864 for darwin_x64 v0.0.0, build time Dec 17 2019 @ 11:03:45
2019:12:17 23:27:17.505 [0x700003f25000- apiCallQ] W/License: failed to find a suitable hardware identifier - trying the operating platform
2019:12:17 23:27:17.505 [0x700003f25000- apiCallQ] I/Engine: default security certificate:
subject..........: [/C=US/ST=Washington/L=Seattle/O=Rally Tactical Systems, Inc./OU=(c) 2019 Rally Tactical Systems, Inc. - For authorized use only/CN=Engage Factory Default Certificate/[email protected]]
issuer...........: [/C=US/ST=Washington/L=Seattle/O=Rally Tactical Systems, Inc./OU=(c) 2019 Rally Tactical Systems, Inc. - For authorized use only/CN=Rally Tactical Systems Root CA 1/[email protected]]
selfSigned.......: [0]
version..........: [1]
notBefore........: [Sep 7 01:53:06 2019 GMT]
notAfter.........: [Sep 4 01:53:06 2029 GMT]
2019:12:17 23:27:17.505 [0x700003f25000- apiCallQ] I/Engine: assigning default certificate for timeline signing
2019:12:17 23:27:17.505 [0x700003f25000- apiCallQ] I/Engine: timeline signing certificate:
subject..........: [/C=US/ST=Washington/L=Seattle/O=Rally Tactical Systems, Inc./OU=(c) 2019 Rally Tactical Systems, Inc. - For authorized use only/CN=Engage Factory Default Certificate/[email protected]]
issuer...........: [/C=US/ST=Washington/L=Seattle/O=Rally Tactical Systems, Inc./OU=(c) 2019 Rally Tactical Systems, Inc. - For authorized use only/CN=Rally Tactical Systems Root CA 1/[email protected]]
selfSigned.......: [0]
version..........: [1]
notBefore........: [Sep 7 01:53:06 2019 GMT]
notAfter.........: [Sep 4 01:53:06 2029 GMT]
2019:12:17 23:27:17.505 [0x700003f25000- apiCallQ] E/Engine: rtpJitterMinMs cannot be less than 20
2019:12:17 23:27:17.505 [0x700003f25000- apiCallQ] I/Engine: using '/var/folders/5b/dgc17xy51qq9fvmtgd74r5m80000gp/T/com.rallytac.engage/engine' as the engine root data directory
2019:12:17 23:27:17.506 [0x700003f25000- apiCallQ] E/Engine: invalid license key and/or activation code '':':''
D/EngageMain: on_ENGAGE_ENGINE_STARTED
2019:12:17 23:27:17.525 [0x70000402b000- engineMainQ] I/Engine: opening database ':memory:'
buildGroupCreationJson: {"alias":"APL-00003D041C26","audio":{"inputGain":0,"inputId":0,"outputId":0,"outputLevelLeft":100,"outputLevelRight":100},"blockAdvertising":false,"cryptoPassword":"","id":"{c568debe-dcd6-45ce-bcd0-84be0114af8f}","interfaceName":"","name":"Test Group 1","presence":{"forceOnAudioTransmit":false,"format":0,"intervalSecs":30,"listenOnly":false},"rallypoints":[],"rx":{"address":"239.42.42.1","port":42000},"source":"","timeline":{"enabled":true,"maxAudioTimeMs":30000,"recordAudio":true},"tx":{"address":"239.42.42.1","port":42000},"txAudio":{"debug":false,"encoder":1,"extensionSendInterval":10,"fdx":false,"framingMs":20,"initialHeaderBurst":5,"maxTxSecs":0,"noHdrExt":false,"trailingHeaderBurst":5,"userTxFlags":0,"userTxPriority":0},"txOptions":{"priority":4,"ttl":128},"type":1}
2019:12:17 23:27:17.527 [0x70000402b000- engineMainQ] I/Engine: intialized database in 1397599.000000 nanoseconds (1.397599 milliseconds)
2019:12:17 23:27:17.527 [0x70000402b000- engineMainQ] I/Engine: timeline recording has been disabled
2019:12:17 23:27:17.527 [0x70000402b000- engineMainQ] W/Engine: discovery has been disabled
2019:12:17 23:27:17.527 [0x70000402b000- engineMainQ] E/Engine: invalid license key and/or activation code '':':''
D/EngageMain: on_ENGAGE_LICENSE_EXPIRED
2019:12:17 23:27:17.527 [0x70000402b000- engineMainQ] I/Engine: {0x7f8506020400} createSpeaker defaulting to device id 2
2019:12:17 23:27:17.527 [0x70000402b000- engineMainQ] W/Group: configure: timeline recording enabled but no timeline object available (likely disabled in engine policy)
D/EngageMain: on_ENGAGE_GROUP_CREATED: {c568debe-dcd6-45ce-bcd0-84be0114af8f}
D/EngageMain: on_ENGAGE_GROUP_JOINED: {c568debe-dcd6-45ce-bcd0-84be0114af8f}
2019:12:17 23:27:17.541 [0x700004237000- udp.GRP:{c568de] I/udp.GRP:{c568debe-dcd6-45ce-bcd0-84be0114af8f}: {0x7f850500a000} connected RX 239.42.42.1:42000 TX 239.42.42.1:42000 - selectSecs set to 7 seconds based on multicast rejoin
D/EngageMain: on_ENGAGE_GROUP_CONNECTED: {c568debe-dcd6-45ce-bcd0-84be0114af8f}
2019:12:17 23:27:17.592 [0x109e4e5c0- ] I/Script: START TX - PTT count = 1
2019:12:17 23:27:17.592 [0x70000402b000- engineMainQ] I/Engine: {0x7f8506020400} createMicrophone defaulting to device id 1
D/EngageMain: on_ENGAGE_GROUP_TX_STARTED: {c568debe-dcd6-45ce-bcd0-84be0114af8f}
2019:12:17 23:27:20.098 [0x109e4e5c0- ] I/Script: END TX
D/EngageMain: on_ENGAGE_GROUP_TX_ENDED: {c568debe-dcd6-45ce-bcd0-84be0114af8f}
2019:12:17 23:27:20.240 [0x109e4e5c0- ] I/Script: START TX - PTT count = 2
2019:12:17 23:27:20.240 [0x70000402b000- engineMainQ] I/Engine: {0x7f8506020400} createMicrophone defaulting to device id 1
D/EngageMain: on_ENGAGE_GROUP_TX_STARTED: {c568debe-dcd6-45ce-bcd0-84be0114af8f}
^C
My-MacBook-Pro:tmp dev$
The Engage-Cmd Scripting Language
As mentioned, the scripting language supported by engage-cmd is simple by design and designed specifically for automating operations in engage-cmd. In other words, it is not a full-feature language but rather a means for replay common operations repetively for purposes of quality assurance and developer testing.
Pre-defined Variables
Pre-defined variables are values provided by engage-cmd and available to the script. These are:
Variable | Description |
---|---|
@MISSION_OVERALL_GROUP_COUNT | Total number of groups (audio, control, & raw types) in the mission configuration |
@MISSION_AUDIO_GROUP_COUNT | Number of audio groups |
@MISSION_CONTROL_GROUP_COUNT | Number of control groups |
@MISSION_RAW_GROUP_COUNT | Number of raw groups |
Script Variables
Variables only store integer
values and may be referenced anywhere in the script. All variables are scoped globally - i.e. there is no concept of variable scoping. Only basic operations on variables are supported including value assignment via the set
instruction, addition via the add
instruction, and subtraction via the sub
instruction.
Assignment
For example, to set a variable named "counter
" to a value of 42, the instruction is:
set counter 42
You can also assign a random positive value within a specific range starting at zero to a variable by using the set
instruction but preceding the operand value with "r
". For example: to assign a random number between 1 and 500:
set counter r500
Addition
Adding to a variable is done using the add
instructions. For example:
add counter 37
... will add 37 to counter
.
Subtraction
Subtracting is similar. For example:
sub counter 16
... will subtract 16 from counter
.
Testing Variable Values
In lieu of conditional statements (such as "if
"), engage-cmd's scripting language supports a simple test/goto control flow. For example, consider the little script below. Here we start out by setting a variable named counter
to 0. We then enter a loop of sorts which is built using goto statements that instruct engage-cmd to jump to "labels" (names that start with ":"). This loop simply adds 1 to counter
on each iteration of the loop and jumps to the "all_done
" label when counter
reaches 100. Before it reaches 100, though, we would print out "Hello World - iteration number " followed by the current value of counter
(referenced with the notation "${variable_name}
"). We'd then sleep (pause) for 1,000 milliseconds, and go back to the "start
" label.
set counter 0
:start
add counter 1
on counter 100 goto all_done
message.debug Hello world - iteration number ${counter}
sleep 1000
goto start
:all_done
Instructions
Instruction | Format | Description | Example |
---|---|---|---|
message.debug | message.debug message to be printed |
Displays a message at logging level debug | message.debug Hello world |
message.info | message.info message to be printed |
Displays a message at logging level informational | message.info Hello world |
message.warn | message.warn message to be printed |
Displays a message at logging level warning | message.warn Hello world |
message.error | message.error message to be printed |
Displays a message at logging level error | message.error Hello world |
message.fatal | message.fatal message to be printed |
Displays a message at logging level fatal | message.fatal Hello world |
cls | Clears the screen | ||
endscript | Ends the script and returns control to the engage-cmd prompt | ||
goto | goto label |
Transfers script control to the named label | goto myPttLoopStart |
sleep | sleep milliseconds |
Pauses operation for a period of time | sleep 2500 |
create | create group_index |
Creates the group resource in Engage for the group at position group_index in the mission file |
create 3 |
createupto | createupto group_index |
Creates all groups up to and including group_index in the mission file |
createupto 5 |
delete | delete group_index |
Delete group group_index |
delete 3 |
join | join group_index |
Join group group_index |
join 3 |
joinupto | joinupto group_index |
Joins all groups up to and including group_index in the mission file |
joinupto 5 |
leave | leave group_index |
Leave group group_index |
leave 3 |
begintx | begintx group_index |
Begin audio transmission on group_index |
begintx 3 |
endtx | endtx group_index |
Ends audio transmission on group_index |
endtx 3 |
muterx | muterx group_index |
Mutes inbound audio on group_index |
muterx 3 |
unmuterx | unmuterx group_index |
Unmutes inbound audio on group_index |
unmuterx 3 |
mutetx | mutetx group_index |
Mutes captured microphone audio on group_index |
mutetx 3 |
unmutetx | unmutetx group_index |
Unmtes captured microphone audio on group_index |
unmutetx 3 |
enginestart | enginestart | Starts the Engage Engine | enginestart |
enginestop | enginestop | Stops the Engage Engine | enginestop |
set add sub onequal onless ongreater waitforengine waitforgroup