Logging and Playing Back a Connection
VRPN has a logging and playback facility that can be used to store and then replay entire sessions. All messages going to or from the server can be stored into a logfile and then replayed again for analysis or debugging. Playback is from the file that was saved, rather than a server over the network. This enables you to capture a user interaction session and they replay it later. This is especially useful for enabling offline analysis of experiments.
You need to modify the client program that is going to do logging so that it explicitly requests it on a per-connection basis. Normally, VRPN hides the mapping between client (Remote) objects and connections; when you are logging, the application needs to be modified to explicitly open the different connections so that logging happens on all of them (if there are more than one). It is necessary to open a synchronized client connection explicitly before opening the objects that use that connection; this must be done only once per connection; all of the objects that share the same connection share the same logfile.
Each synchronized connection is opened by explicitly calling its constructor and passing it the name of the machine to connect to (or the full name of the object to be logged) and the name of the logfile(s) to create:
The object_name parameter can be the full name for the device you want to connect to (for example, "Button0@machinename"). The port_number parameter tells which port on the machine (machinename in the above example) to connect to - the default port number in VRPN is 4500. The four logfile names specify the filename (local to either the client or server process) into which the following messages will be logged:
If no messages are lost, the local_in_logfile and remote_out_logfile will contain the same messages; the remote_in_logfile and local_out_logfile will also contain the same messages. For messages that were sent unreliably, only the outgoing files are guaranteed to have the messages. Normally, at most two logfiles would be opened; often, only the local_in_logfile is opened (it will hold all messages received by the client). There are different files for incoming and outgoing messages because otherwise it is impossible to determine which messages went in each direction. A NULL pointer should be passed in for any logfiles that are not being opened.
Once the connection object has been opened, the objects using it should be opened normally.
If you want to stop the logfile and start a new one, you need to delete the connection object and create a new one (this will also require deleting all of the objects that use the connection beforehand and recreating them afterwards).
The printvals program has an example of how to create one or more logfiles based on command-line arguments.
Flushing log to disk
The logfile is usually flushed to disk when the connection object that was doing the logging is destroyed. User code can cause logging to happen incrementally by calling the save_log_so_far() method on the vrpn_Connection object doing the logging.
Playback requires no changes to the client code other than changing the name of the device connection from a machine/port connection to a file connection. For example, rather than opening "Button0@machinename", the program will open "Button0@file:filename", where filename is the name that was passed to the constructor in order to save the logfile. It doesn't matter if the logfile was an incoming client-side log or an outgoing server-side log, the device will behave the same. It is also possible to use a full URL to specify that a file is to be opened (Button0@file://filename). To specify a filename starting at the root of the file system, use "Button0@file:///filename". On Windows, you might use "Button0@file://C:/temp/filename".
By default, playback will occur at the same rate that the original messages were sent.
To control the replay rate of the file, you do need to modify the client. The methods on the FileConnection enable you to rewind the streamfile, skip to a particular time, pause, or replay at a specified multiple of real-time. An example of creating a FileController to control playback on the messages sent to a button remote follows: