From 37089885e7a39b971638113157306fec531e7e98 Mon Sep 17 00:00:00 2001 From: Chadwick Boulay Date: Tue, 19 Nov 2019 16:11:20 -0500 Subject: [PATCH] docs bump --- .idea/$CACHE_FILE$ | 6 - .idea/.gitignore | 2 - README.md | 2 +- docs/dev/dev_guide.rst | 65 ++++++++++- docs/dev/examples.rst | 153 +++++++++++++++++++++++++ docs/images/balert.png | Bin 4381 -> 0 bytes docs/index.rst | 5 +- docs/info/faqs.rst | 42 +++++++ docs/info/getting_started.rst | 26 +++++ docs/info/intro.rst | 13 --- docs/info/matlab_example_with_muse.rst | 28 +++++ docs/info/ovas.rst | 2 +- docs/info/supported_devices.rst | 1 + docs/info/user_guide.rst | 37 ++++++ 14 files changed, 357 insertions(+), 25 deletions(-) delete mode 100644 .idea/$CACHE_FILE$ delete mode 100644 .idea/.gitignore create mode 100644 docs/dev/examples.rst delete mode 100644 docs/images/balert.png create mode 100644 docs/info/faqs.rst create mode 100644 docs/info/getting_started.rst create mode 100644 docs/info/matlab_example_with_muse.rst diff --git a/.idea/$CACHE_FILE$ b/.idea/$CACHE_FILE$ deleted file mode 100644 index 6cb8985..0000000 --- a/.idea/$CACHE_FILE$ +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 5c98b42..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Default ignored files -/workspace.xml \ No newline at end of file diff --git a/README.md b/README.md index 0c28223..e941c1d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ access as well as optionally the centralized collection, viewing and disk record The most common way to use LSL is to use one or more applications with integrated LSL functionality. -* Take a look at the list of [supported devices](https://github.com/sccn/labstreaminglayer/wiki/SupportedDevices) +* Take a look at the list of [supported devices](https://labstreaminglayer.readthedocs.io/en/latest/info/supported_devices.html) and follow the instructions to start streaming data from your device. If your device is not in the list then see the "Getting Help" section below. * Download [LabRecorder](https://github.com/labstreaminglayer/App-LabRecorder) from its diff --git a/docs/dev/dev_guide.rst b/docs/dev/dev_guide.rst index a34742d..189e0d4 100644 --- a/docs/dev/dev_guide.rst +++ b/docs/dev/dev_guide.rst @@ -5,4 +5,67 @@ Add introductory text here. The distribution includes a range of code examples in C, C++, Python, MATLAB, Java, and C# including some very simple sender and receiver programs, as well as some fairly extensive demo apps. -See `ExampleCode `__ for a broader overview of example programs, API documentation link, and general programming tips, tricks, and frequently asked questions. +See `Example Applications `__ for a broader overview of example programs, API documentation link, and general programming tips, tricks, and frequently asked questions. + +# Coding Guides +The distribution includes a range of code examples in C, C++, Python, MATLAB, Java, and C# including some very simple sender and receiver programs, as well as some fairly extensive demo apps. This page includes just some simple teasers. See [[ExampleCode|ExampleCode]]for a broader overview of example programs, API documentation link, and general programming tips, tricks, and frequently asked questions. + +## Sending Random Data in C++ +``` +#include "lsl_cpp.h" +#include +using namespace lsl; + +/** + * This is an example of how a simple data stream can be offered on the network. + * Here, the stream is named SimpleStream, has content-type EEG, and 128 channels. + * The transmitted samples contain random numbers (and the sampling rate is irregular + * and effectively bounded by the speed at which the program can push out samples). + */ + +int main(int argc, char* argv[]) { + + // make a new stream_info (128ch) and open an outlet with it + stream_info info("SimpleStream","EEG",128); + stream_outlet outlet(info); + + // send data forever + float sample[128]; + while(true) { + // generate random data + for (int c=0;c<128;c++) + sample[c] = (rand()%1500)/500.0-1.5; + // send it + outlet.push_sample(sample); + } + + return 0; +} +``` + +## Receiving Data in C++ +``` +#include "lsl_cpp.h" + +/** + * This is a minimal example that demonstrates how a multi-channel stream (here 128ch) + * of a particular name (here: SimpleStream) can be resolved into an inlet, and how the + * raw sample data & time stamps are pulled from the inlet. This example does not + * display the obtained data. + */ + +int main(int argc, char* argv[]) { + using namespace lsl; + + // resolve the stream of interest & make an inlet to get data from the first result + std::vector results = resolve_stream("name","SimpleStream"); + stream_inlet inlet(results[0]); + + // receive data & time stamps forever (not displaying them here) + float sample[128]; + while (true) + double ts = inlet.pull_sample(&sample[0],128); + + return 0; +} +``` diff --git a/docs/dev/examples.rst b/docs/dev/examples.rst new file mode 100644 index 0000000..386e71c --- /dev/null +++ b/docs/dev/examples.rst @@ -0,0 +1,153 @@ +LSL Coding Fundamentals +####################### + +There are essentially two types of programs interacting with LSL: programs that provide data, such as a data source that represents a particular acquisition device, and programs that consume data (and occasionally mixtures of the two), such as a viewer, a recorder, or a program that takes some action based on real-time data. + +The main difference between LSL and other data transport interfaces is that it is not connection-oriented (although the underlying implementation uses connection-oriented transport). It is closer to a "publish-subscribe" model. A data producer creates a named "outlet" object (perhaps with meta-data) and pushes samples into it without ever caring about who is listening. So functionally it is offering a stream of data plus some meta-data about it. + +A data consumer who is interested in a particular type of stream queries the network for a matching one ("resolves it"), for example based on the name, type or some other content-based query and then creates an "inlet" object to receive samples from the stream. It can also separately obtain the meta-data of the stream. The consumer then pulls out samples from the stream. The sequence of samples that the consumer sees is in order, without omissions (unless a buffer's memory is exhausted), and type-safe. The data is buffered at both endpoints if there are transmission delays anywhere (e.g., interrupted network connection) but otherwise delivered as fast as the system allows. + +The objects and functions to perform these tasks are provided by a single cross-platform library (liblsl). The library comes with a C header file, a C++ header file and wrapper classes for other languages. + +Note: if you have trouble establishing communication between these programs across different computers especially on Windows, take a look at the NetworkConnectivity page and read the Network Troubleshooting section. + +API Documentation +################# + +It is recommended that you clone the repository to get the respective code (or check the `SDK mirror `__ at SCCN). The documentation is at the following locations: + * C: `C header file `__ + * C++: `C++ header file `__ + * Python: `pylsl module `__ + * Java: `JavaDocs `__ + * C#: `LSL module `__ + * MATLAB: `class files `__. + * Other languages (R, Octave, Ruby, Lua, Perl, Go): `SWIG interfaces `__ (the C or C++ header file is the API reference). + +The API documentation covers all classes, functions and types and should hopefully leave no questions unanswered. Note that a typical application will only need a small subset of the API (as used in the example programs). + +C Example Programs: Basic to Advanced +##################################### + +These two example programs illustrate the bread-and-butter use of LSL as it is executing in almost any device module that comes with the distribution: + * `Sending a multi-channel time series into LSL. `__ + * `Receiving a multi-channel time series from LSL. `__ + +These two example programs illustrate a more special-purpose use case, namely sending arbitrary string-formatted data at irregular sampling rate. Such streams are used by programs that produce event markers, for example: + * `Sending a stream of strings with irregular timing. `__ + * `Receiving a stream of strings with irregular timing. `__ + +The last example shows how to attach properly formatted meta-data to a stream, and how to read it out again at the receiving end. While meta-data is strictly optional, it is very useful to make streams self-describing. LSL has adopted the convention to name meta-data fields according to the XDF file format specification whenever the content type matches (for example EEG, Gaze, MoCap, VideoRaw, etc); the spec is `here `__. Note that some older example programs (SendData/ReceiveData) predate this convention and name the channels inconsistently. + * `Handling stream meta-data. `__ + +C++ Example Programs: Basic to Advanced +####################################### + +These two example programs illustrate the shortest amount of code that is necessary to get a C++ program linked to LSL: + * `Minimal data sending example. `__ + * `Minimal data receiving example. `__ + +These two example programs demonstrate how to write more complete LSL clients in C++ (they are 1:1 equivalents of the corresponding C programs): + * `Sending a multi-channel time series into LSL. `__ + * `Receiving a multi-channel time series from LSL. `__ + +These two programs transmit their data at the granularity of chunks instead of samples. This is mostly a convenience matter, since inlets and outlets can be configured to automatically batch samples into chunks for transmission. Note that for LSL the data is always a linear sequence of samples and data that is pushed as samples can be pulled out as chunks or vice versa. They also show how structs can be used to represent the sample data, instead of numeric arrays (which is mostly a syntactic difference): + * `Sending a multi-channel time series at chunk granularity. `__ + * `Receiving a multi-channel time series at chunk granularity. `__ + +These two example programs illustrate a more special-purpose use case, namely sending arbitrary string-formatted data at irregular sampling rate. Such streams are used by programs that produce event markers, for example. These are 1:1 equivalents of the corresponding C programs: + * `Sending a stream of strings with irregular timing. `__ + * `Receiving a stream of strings with irregular timing. `__ + +The last example shows how to attach properly formatted meta-data to a stream, and how to read it out again at the receiving end. While meta-data is strictly optional, it is very useful to make streams self-describing. LSL has adopted the convention to name meta-data fields according to the XDF file format specification whenever the content type matches (for example EEG, Gaze, MoCap, VideoRaw, etc); the spec is `here `__. Note that some older example programs (SendData/ReceiveData) predate this convention and name the channels inconsistently. + * `Handling stream meta-data. `__ + +C/C++ Special-Purpose Example Programs +###################################### +These programs illustrate some special use cases of LSL that are also relevant for C programmers. See the lsl\_c.h header for the corresponding C APIs (they are very similar to the C++ code shown here). + +This example illustrates in more detail how streams can be resolved on the network: + * `Resolving all streams on the lab network, one-shot and continuous. `__ + +This example shows how to query the full XML meta-data of a stream (which may be several megabytes large): + * `Retrieving the XML meta-data of a stream. `__ + +This example shows how to obtain time-correction values for a given stream. These time-correction values are offsets (in seconds) that are used to remap any stream's timestamps into the own local clock domain (just by adding the offset to the timestamp): + * `Querying the time-correction information for a stream. `__ + +Python Example Programs: Basic to Advanced +########################################## +These examples show how to transmit a numeric multi-channel time series through LSL: + * `Sending a multi-channel time series into LSL. `__ + * `Receiving a multi-channel time series from LSL. `__ + +The following examples show how to send and receive data in chunks, which can be more convenient. The data sender also demonstrates how to attach meta-data to the stream. + * `Sending a multi-channel time series in chunks. `__ + * `Receiving a multi-channel time series in chunks. `__ + +These examples show a special-purpose use case that is mostly relevant for stimulus-presentation programs or other applications that want to emit 'event' markers or other application state. The stream here is single-channel and has irregular sampling rate, but the value per channel is a string: + * `Sending string-formatted irregular streams. `__ + * `Receiving string-formatted irregular streams. `__ + +The last example shows how to attach properly formatted meta-data to a stream, and how to read it out again at the receiving end. While meta-data is strictly optional, it is very useful to make streams self-describing. LSL has adopted the convention to name meta-data fields according to the XDF file format specification whenever the content type matches (for example EEG, Gaze, MoCap, VideoRaw, etc); the spec is `here `__. Note that some older example programs (SendData/ReceiveData) predate this convention and name the channels inconsistently. + * `Handling stream meta-data. `__ + +MATLAB Example Programs: Basic to Advanced +########################################## +These examples show how to transmit a numeric multi-channel time series through LSL: + * `Sending a multi-channel time series into LSL. `__ + * `Receiving a multi-channel time series from LSL. `__ + +These examples do the same as before, but now transmit the data at the granularity of chunks. For the purposes of network transmission the same effect can be achieved by creating the inlet or outlet with an extra argument to indicate that multiple samples should be batched into a chunk for transmission. However, since MATLAB's interpreter is relatively slow, the library calls should be made in a vectorized manner, i.e. at chunk granularity, whenever possible (at least for high-rate streams). Note that for LSL the data is always a linear sequence of samples and data that is pushed as samples can be pulled out as chunks or vice versa: + * `Sending data at chunk granularity. `__ + * `Receiving data at chunk granularity. `__ + +These examples show a special-purpose use case that is mostly relevant for stimulus-presentation programs or other applications that want to emit 'event' markers or other application state. The stream here is single-channel and has irregular sampling rate, but the value per channel is a string: + * `Sending string-formatted irregular streams. `__ + * `Receiving string-formatted irregular streams. `__ + +The last example shows how to attach properly formatted meta-data to a stream, and how to read it out again at the receiving end. While meta-data is strictly optional, it is very useful to make streams self-describing. LSL has adopted the convention to name meta-data fields according to the XDF file format specification whenever the content type matches (for example EEG, Gaze, MoCap, VideoRaw, etc); the spec is `here `__. Note that some older example programs (SendData/ReceiveData) predate this convention and name the channels inconsistently. + * `Handling stream meta-data. `__ + +Java Example Programs: Basic to Advanced +######################################## +These examples show how to transmit a numeric multi-channel time series through LSL: + * `Sending a multi-channel time series into LSL. `__ + * `Receiving a multi-channel time series from LSL. `__ + +The following examples show how to transmit data in form of chunks instead of samples, which can be more convenient. + * `Sending a multi-channel time series in chunks. `__ + * `Receiving a multi-channel time series in chunks. `__ + +These examples show a special-purpose use case that is mostly relevant for stimulus-presentation programs or other applications that want to emit 'event' markers or other application state. The stream here is single-channel and has irregular sampling rate, but the value per channel is a string: + * `Sending string-formatted irregular streams. `__ + * `Receiving string-formatted irregular streams. `__ + +The last example shows how to attach properly formatted meta-data to a stream, and how to read it out again at the receiving end. While meta-data is strictly optional, it is very useful to make streams self-describing. LSL has adopted the convention to name meta-data fields according to the XDF file format specification whenever the content type matches (for example EEG, Gaze, MoCap, VideoRaw, etc); the spec is `here `__. Note that some older example programs (SendData/ReceiveData) predate this convention and name the channels inconsistently. + * `Handling stream meta-data. `__ + +C# Example Programs: Basic to Advanced +###################################### +These examples show how to transmit a numeric multi-channel time series through LSL: + * `Sending a multi-channel time series into LSL. `__ + * `Receiving a multi-channel time series from LSL. `__ + +The following examples show how to transmit data in form of chunks instead of samples, which can be more convenient. + * `Sending a multi-channel time series in chunks. `__ + * `Receiving a multi-channel time series in chunks. `__ + +These examples show a special-purpose use case that is mostly relevant for stimulus-presentation programs or other applications that want to emit 'event' markers or other application state. The stream here is single-channel and has irregular sampling rate, but the value per channel is a string: + * `Sending string-formatted irregular streams. `__ + * `Receiving string-formatted irregular streams. `__ + +The last example shows how to attach properly formatted meta-data to a stream, and how to read it out again at the receiving end. While meta-data is strictly optional, it is very useful to make streams self-describing. LSL has adopted the convention to name meta-data fields according to the XDF file format specification whenever the content type matches (for example EEG, Gaze, MoCap, VideoRaw, etc); the spec is `here `__. Note that some older example programs (SendData/ReceiveData) predate this convention and name the channels inconsistently. + * `Handling stream meta-data. `__ + +Real-World Example Programs +########################### +These sample codes are from actual 'production' software that is used to do data transmission: + * `Kinect: multi-channel signal with body joint positions and meta-data. `__ + * `Keyboard: irregular marker stream based on keyboard inputs. `__ + * `B-Alert: reading from an EEG device in a separate thread. `__ + * `EyeLink: reading from an eye tracker in Python. `__ + +Also, all applications in the Apps directory are open-source and can serve as examples, and most of them are very similar in how they pass on data to LSL. \ No newline at end of file diff --git a/docs/images/balert.png b/docs/images/balert.png deleted file mode 100644 index 64c10e5b4f111554ef782f2a829daa8718120adb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4381 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 and follow the instructions to start streaming data from your device. If your device is not in the list then see the "Getting Help" section below. +* Download `LabRecorder `_ from its `release page `_. (Note that LabRecorder saves data to `Extensible Data Format (xdf) `_ which has its own set of tools for loading data after finishing recording.) +* Use LSL from your scientific computing environment. LSL has many language interfaces, including Python and Matlab. + * Python users need only `pip install pylsl` then try some of the `provided examples `_. + * The `Matlab interface `_ is also popular but requires a little more work to get started; please see its README for more info. + +If you are not sure what you are looking for then try browsing through the code which has submodule links to different repositories for tools and devices (Apps) and language interfaces (LSL). When you land in a new repository then be sure to read its README and look at its Releases page. + +Getting Help +############ + +If you are having trouble with LSL, there are few things you can do to get help. + +* `Read the docs `_ +* Search GitHub issues in this repository, in the old `archived repository `_, and in the submodule for your App or language interface of interest. +* Create a new GitHub issue. Please use the repository specific to the item you are having difficulty with. e.g. if you are having trouble with LabRecorder then open a new issue in its repository. If you don't know which repository is best then you can use the parent sccn/labstreaminglayer repository. +* Join the LabStreamingLayer `#users` channel on Slack. `Invite Link `_. Someone there may be able to get to the bottom of your problem through conversation. +* You may also wish to subscribe to the `LSL mailing list `_ diff --git a/docs/info/intro.rst b/docs/info/intro.rst index f321146..333dadd 100644 --- a/docs/info/intro.rst +++ b/docs/info/intro.rst @@ -51,16 +51,3 @@ Developer Information ===================== Please see the separate `build documentation `__. - -Clock synchronization ---------------------- - -Here we talk about important functions like the local clock -(:func:`lsl_local_clock`), a function to query a time offset -(:func:`lsl_time_correction_ex`) and a function to get the library version used -by the loaded library (:func:`lsl_library_version`). - -Creating outlets ----------------- - -The main outlet class is :class:`lsl::stream_outlet`. diff --git a/docs/info/matlab_example_with_muse.rst b/docs/info/matlab_example_with_muse.rst new file mode 100644 index 0000000..6b08bd7 --- /dev/null +++ b/docs/info/matlab_example_with_muse.rst @@ -0,0 +1,28 @@ +This is the series of steps to connect with the Muse. + +1. Download the Muse SDK from http://developer.choosemuse.com +2. Pair your computer with your Muse headset and connect to your Muse using muse-io (replace Muse-XXXX with the name of your Muse device as it shows in the Bluetooth settings) + ``muse-io --device Muse-XXXX --lsl-eeg EEG`` + +A successful connection should show like + +.. image:: ../images/muse1lsl.png + +3. Now the stream should be visible on your local network. To check this is the case, the easiest is to download the `LSL LabRecorder `_ for data acquisition. This will show you which streams are available and save them in XDF format if you wish to. +#. Download `liblsl-Matlab `_ +#. Start Matlab and add the folder liblsl-Matlab **with subfolder** to the Matlab path. +#. Clone the `Matlab viewer `_. +#. Go to the folder above and execute ``vis_stream`` from the Matlab command prompt + +**Alternative solution** + +1. and 2. are identical + +3. Clone `BCILAB `_. BCILAB contains a version of the Matlab viewers as well as liblsl binaries for Matlab. +#. Start matlab and go to the folder above and type ``bcilab`` +#. Go to the subfolder code/visualization of BCILAB and run _vis_stream_ (select all defaults and press OK) +#. If you have problem (such as Error using supergui (line 122) supergui error: argument 'fig' must be numeric), it could be due to the fact that you are using a newer Matlab version that is not compatible with some functions of BCILAB. If this is the case, then install the latest version of `EEGLAB `_ which will overload the functions that cause problem. Go to the newly downloaded EEGLAB folder and type ``eeglab``. Try again to run ``vis_stream`` as in Step 3. + +You should now be able to stream Muse data + +.. image:: ../images/muse2lsl.png diff --git a/docs/info/ovas.rst b/docs/info/ovas.rst index 828c57f..b138295 100644 --- a/docs/info/ovas.rst +++ b/docs/info/ovas.rst @@ -6,7 +6,7 @@ To enable LSL output, click on Preferences in the OVAS application, check the bo .. image:: ../images/OVAS-main.png -.. image:: ../images/OVAS-driverprops.png +.. image:: ../images/ovas-driverprops.png Minimizing Latency ****************** diff --git a/docs/info/supported_devices.rst b/docs/info/supported_devices.rst index 6a86105..d6298e0 100644 --- a/docs/info/supported_devices.rst +++ b/docs/info/supported_devices.rst @@ -11,6 +11,7 @@ The following devices support LSL via vendor-provided software: * `Cognionics (all headsets) `__ * `EB Neuro BE Plus LTM `__ * `InteraXon Muse `__ + * `Example use with Matlab `__ * `mBrainTrain SMARTING `__ * `neuroelectrics Enobio `__ * `OpenBCI (all headsets) `__ diff --git a/docs/info/user_guide.rst b/docs/info/user_guide.rst index 698ff51..9187c27 100644 --- a/docs/info/user_guide.rst +++ b/docs/info/user_guide.rst @@ -1,6 +1,43 @@ User's Guide ############ +Basic Operation +*************** + +The networking in LSL works as follows. The only active participants in LSL networking are the outlet objects, the inlet objects, as well as calls to a resolve function (these are all implemented in the liblsl library). Most details of the communication are configurable, so in the following only the default behavior is explained for conciseness. + +Outlets +======= +An outlet may use either IPv4, or IPv6, or both IP stacks in parallel. In the latter case some of the sockets and threads are duplicated. + +UDP Service Discovery +--------------------- +An outlet creates a group of UDP sockets on which it listens for incoming content-based queries. Such queries are used to find a stream of interest that has the desired meta-data (e.g., a particular content type or number of channels). An outlet matches each inbound query to its stream's meta-data and responds only in case of a match. Repeated queries are served by a query cache for efficiency. + +In particular, outlets listen via UDP on the multicast port (16571) for broadcast and multicast queries. Multiple sockets are created for this purpose, each of which listens on a different multicast address; these include both IPv4 and IPv6 addresses of the desired scope (for robustness to network conditions). The sockets are served from a single thread using asynchronous I/O for efficiency. While this still sounds like a lot of overhead, note that this thread is in waiting state for most of the time. + +In addition, outlets create a single regular (unicast) UDP socket that listens for content queries on a free port in the port range 16572-16604. This is a fallback in case the broadcast/multicast service discovery is disabled. This socket not only handles content queries but also responds to time estimation packets (used by inlets to estimate clock synchronization when a transmission is ongoing). + + +TCP Data Transmission +--------------------- +In addition each outlet creates a TCP server socket on a free port in the port range 16572-16604 to accept actual data transmission requests. There are two types of transmission requests: a request for streaming data (such a connection would be established when an inlet is used to pull samples from a particular provider) and a request for meta-data (such a connection would be established when an inlet is used to retrieve the full meta-data of a stream). TCP servers can also in principle handle service discovery, but are not used for this purpose due to the relative inefficiency of this. + +An outlet can handle an arbitrary number of parallel connections to serve any number of listeners. + +Resolve Operations +================== +When a client resolves a stream with desired properties on the lab network, it issues a resolve operation. A resolve operation temporarily opens a range of UDP sockets through which queries are sent to the broadcast, multicast or unicast addresses that are configured as active. It also opens a UDP socket to receive result packets on a free port. The resolve operation emits a packet across each channel in a brief burst and waits for responses, then sends the next burst. This is repeated until the required conditions are fulfilled (e.g., service was found, timeout, etc.). + +Inlets +====== +An inlet, when created, initially does not create any sockets. Sockets are created as needed for the following purposes: + +* When a transmission of streaming data is started by calling pull\_sample() or open\_stream(), a TCP connection is established to the outlet in question and if successful, data is received over this connection until it breaks off or is explicitly terminated. +* If the XML meta-data of the inlet is requested, another TCP connection is established which persists until the meta-data has been transferred from the outlet. +* When the inlet is used to estimate time-correction values (as the recorder program does), a UDP socket is opened which periodically (every few seconds) exchanges a brief series of packets with the outlet's unicast UDP socket. +* If the connection to the outlet breaks off or is otherwise unsuccessful (for example due to a computer crash at the other end), and if the outlet was "recoverable", a resolve operation will be periodically scheduled every few seconds until the outlet in question is found again or the inlet is destroyed, or the active transmission is stopped. + Clock synchronization ---------------------