# `AdaptiveRepresentationSelector`

| Consideration           | Status                          |
| ----------------------- | ------------------------------- |
| Preferred import style  | Directory-only _[1]_            |
| Multithread environment | Should be runnable in WebWorker |

_[1]_ Only the `adaptive` directory itself should be imported and relied on by the rest of
the code, not its inner files (thus `./index.ts` should export everything that may be
imported by outside code).

## Overview

The `AdaptiveRepresentationSelector` is a function which facilitates the choice between
multiple audio/video qualities in function of the network capabilities and other specific
settings set by the client.

It does so by receiving various values such as:

- when network requests begin, progresses or end
- stats about the bandwidth of the user
- the current status of the buffer (how much of the buffer is left etc.)
- DOM events
- user settings (maximum authorized bitrate/width etc.)
- the available qualities

With all those variables at hand, it then proposes the quality which seems to be the most
adapted, that is the quality which:

- will respect user settings (example: a Maximum bitrate is set)
- will maximize the user experience (example: a quality too high for the network to handle
  would lead to excessive re-bufferings, but a too low would be not as pleasant to watch)

In order to estimate the quality that maximizes the playback experience, we rely on
multiple algorithms:

1. One which picks a quality from network conditions.
2. Another relies on buffering conditions to make its choices.
3. A third, only used in very rare conditions, "guess" the right quality by progressively
   raising the quality until an un-maintainable one is found.

## Bandwidth-based algorithm

```
                 Long
                 (normal mode) [2]
                         +----------+ Buffer Gap [1] +-------+
                         |                                   |
                         v                                   |Short
                     Request(s)                              |(starvation mode)
                     datas                                   |[4]
                         +                                   |
                         |                                   |
                         |                                   |
    Request time length  |                                   |
    Data size            |                                   |
                         |                                   |
+- - - - - - - - - - - + v +- - - - - - - - - - -+           v
| Short term EWMA [2a] |   | Long term EWMA [2b] |     Last request
+- - - - - - - - + - - +   +- - -+- - - - - - - -+           +
                 |               |                           |
             + - + - - - - - - - + - +       +- - - - - - - -v- - - - - - +
             | Ceil bitrate (minimum |       | Ceil bitrate               |
             | between both) [3]     |       | (bandwidth estimation from |
             + - - - - - + - - - - - +       | last request [5]           |
                         |        ^          + - - - - - - - - - -+- - - -+
                         |        |                   ^           |
                         v        |                   |           v
                      Ceiled      +---+ Available +---+      Ceiled
                      bitrate           qualities            bitrate
                         +                                       +
                         |                                       |
                         |                                       |
                         +---------> Chosen quality <------------+
```

[1] The buffer gap is the distance between the current time and the buffer time edge.

[2] If the buffer gap is long (more than 5 seconds in default configuration): From
requests computed bandwidths (data size / request time), calculate two
[EWMA](https://en.wikipedia.org/wiki/EWMA).

[2a] The first, a fast-moving average, falls quickly when estimated bandwidth falls
suddenly.

[2b] The second, a slow-moving average, is a bandwidth mean.

[3] For quality of service, the player should adapt down quickly, to avoid buffering
situations, and grow up slowly, in order to smoothly change quality. For this reason, the
minimum between the two estimated is considered as a bitrate threshold. The chosen quality
is a quality's bitrate ceiling.

[4] If the buffer gap is too short, it is considered as "starving":

[5] An immediate bandwidth is computed from last or current request. The quality's bitrate
ceiling relies on it to return the chosen quality.

## Buffer-based algorithm

```
                              Qualities
                                  |
                                  |
                                  v
                       +- - - - - + - - - - - - +
    buffer gap [2]     | compute BOLA steps [1] |   maintainability score [3]
         |             +- - - - - - - - - - - - +           +
         |                        |                         |
         |                        v                         |
         |            +- - - - - - - - - - - - -+           |
         +----------> | Compute optimal quality | <---------+
                      +- - - - - - - - - - - - -+
```

[BOLA Algorithm](https://arxiv.org/pdf/1601.06748.pdf) finds optimal quality value to
minimize playback buffering and maximize buffered quality.

[1] BOLA broadly defines minimum buffer steps for which we can allow to download a
quality:

```
                ^
Bitrates (kb/s) |
                |
           3200 |                           +-------------------------+
                |                           |
           1500 |                    +------+
                |                    |
            750 |             +------+
                |             |
            300 |      +------+
                |      |
                +------+------------------------------------------------->
                       5      10     15     20

                                 Buffer gap (s)
```

[2] The BOLA estimation is computed each time a segment is appended (thus buffer gap is
updated).

The RxPlayer has a mecanism that allows to replace low-quality buffered segments by higher
quality ones if the current conditions improve. That leads to the buffer gap not
increasing when a chunk is added. That could mislead BOLA, and cause oscillations between
chosen qualities.

[3] In order to avoid this trend, we compute a maintainability score for the currently
downloaded quality. It is an [EWMA ](https://en.wikipedia.org/wiki/EWMA) of the ratio
between segment duration and segment download time. If the score points that a quality is
"maintainable", the algorithm shall not decide to decrease quality and is "allowed" to
pick an upper quality. Conversely, when a quality may not be downloadable fast enough, the
BOLA is "allowed" to decrease the estimated quality, and shall not decide to increase it.

If no maintanaibility score is computed, then BOLA works the regular way.
