For controlling the behaviour of VisionLib during runtime, we provide a variety of different commands. A list of available commands can be found at Command Reference. In Unity we reflected these commands in the corresponding tracker components:
Some commands will influence the execution of the current tracking algorithm. To not interfere with the current execution, every command sent to VisionLib will be stored and performed after the tracking of the current frame has been finished. So some time might elapse between sending a command and receiving a result.
To reflect this behaviour inside Unity, we are using the Task
interface. This allows every developer to perform code after a command has successfully returned without complex registering of callback functions. It also allows the user to receive the result of a performed command and process it as soon as the asnychronous command has returned the result. This way, commands are easier to use and understand than implementing this with callback functions.
A Task
in C# can be seen as an interface to a function processed in the background. You can copy or move the Task
, without affecting its processing. If you Start
a Task
, it will be executed and usually performed in a thread of a thread pool.
A Task
contains either a result (which might also be void
) or an Exception
(if the task is "canceled" it also contains an Exception
). If you await
a Task
(see section below), the Task
will return its result or rethrow its exception. So the Task asynchronous programming model (TAP) provides an abstraction over asynchronous code. You write code as a sequence of statements, just like always.
You can wait for a Task
completion in two ways:
await
a Task
in an async
function, the execution of the calling function continues (like a return
for the current thread). After the Task
has been completed, an arbitrary thread continues the execution inside the function after the await
.Wait
on a Task
object, the execution of the current thread will pause until the Task
has been finished. We recommend to not use Wait
since this might make your GUI freeze and lead to deadlocks in your program.If you want to use a command inside your program flow, you should start with an async Task
function.
Inside this function you can wait for a command to finish with the keyword await
. The program flow inside this function will be synchronous:
You can again use your new MyFunctionAsync
in another async Task
function to structure your code. But at some point you just want to process the task in the background. This is especially relevant, if you want to call a function from the Unity Editor or in the GUI. Therefore you have to add an additional function:
Awaiting commands (with await
) might throw either a WorkerCommands.CommandError
exception (if the command could not be executed correctly) or a System.Threading.Task.TaskCanceledException
(indicating, that the command has not been executed). Therefore we provide a helper function which takes care about those exceptions: TrackingManager.CatchCommandErrors
. Calling this function will execute the MyFunctionAsync
in the background and will send a notification if an error in the execution of a command occurred.
Important: At this point (Changing from Task
to void
functions), the execution order might not be as expected:
Calling MyFunction
will result in the following Log output:
The execution will return at the await
and continues at the calling function. All the code below the await
will be executed after the ResetHard
command has been finished. So we recommend to put every call that chronologically depends on a command inside an async Task MyFunctionAsync
function. The void MyFunction
should only contain the TrackingManager.CatchCommandErrors(MyFunctionAsync())
call and should only be used when the execution order is not relevant or when calling a public method via the Unity inspector.