Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] v4 code reorganization #1365

Merged
merged 12 commits into from
Jan 31, 2024
Merged

[WIP] v4 code reorganization #1365

merged 12 commits into from
Jan 31, 2024

Conversation

peaBerberian
Copy link
Collaborator

@peaBerberian peaBerberian commented Jan 25, 2024

As discussed (with the core RxPlayer team), now is one of the very rare occasions in the project life where we have few long-lived branch to regularly rebase (or at least not in the scale of the enormous v4 or worker branches).
This is because if the v4.0.0-rc1 is the confirmed v4.0.0, we won't rebase v4 branches on the v3 anymore, both will evolve separately).

So we had several discussions on what heavy code updates we can now try and came up with several.

Remaining steps:

  • src/manifest usage is still weird due to the Object/class schism
  • prettier needs to be installed and to be linked to our CI

Core code division for webworker vs main thread

The MULTI_THREAD experimental feature required some extensive changes that may profit from reorganizing directories. For example, there's no clear division between files intended to run in main thread and those intended to run in a WebWorker environment, and one file could easily import the wrong kind of file, making the bundle size bigger or worse, leading to runtime errors.

I thus splitted-up the src/core directory of the RxPlayer into two directories:

  1. src/main_thread which contains the part of the core that always runs in main thread (i.e. even in MultiThreading mode).

    It contains today:

    • src/main_tread/api: the RxPlayer public API. Previously in src/core/api

    • src/main_tread/decrypt: the ContentDecryptor module previously in src/core/decrypt

    • src/main_tread/init: Only the ContentInitializer interface implementations found previously in src/core/init and the utils that always have to be performed in main thread (init utils which may now be performed on a webworker are in src/core/main/common)

    • src/main_tread/text_displayer: the TextDisplayer definitions previously in src/text_displayer

    • src/main_tread/tracks_store: the TracksStore classes previously in src/core/api/track_management

    • A types.ts file which should generally be all the external code may need to import

  2. src/core which contains the part of the core that may run in a WebWorker
    It contains today:

    • src/core/adaptive: unchanged

    • src/core/main: the part of the previous src/core/init directory which may now run in a WebWorker. Utils that may be run in a monothreading mode are in an common subdirectory (which may be directly imported by the src/main_thread/init code - which doesn't lead to pretty import paths so we may change that in the future). Files only intended to run in a WebWorker are in a worker subdirectory.

    • src/core/fetchers: unchanged

    • src/core/segment_sinks: the new name of the src/core/segment_buffers directory (see SegmentBuffers renaming chapter below)

    • src/core/stream: unchanged

    • A types.ts file which should generally be all the external code may need to import

This new file organization make it clearer by looking at imported paths when something that shouldn't be imported is imported (core shouldn't rely on main_thread besides type definitions, basically).
It may also be an important step to rely on TypeScript to enforce that WebWorker files do not relies on main-thread-only types (not done for now).

SegmentBuffers are renamed to SegmentSinks

SegmentBuffers are far from being the actual media buffers but can more be seen as the destination of loaded segments. Moreover both the src/mse and src/main_thread/text_displayer directories (added since the worker branch) may fill more the role of what could be called "media buffers". Consequenly I chose to rename SegmentBuffers and the SegmentBuffersStore class to SegmentSinksStore.

src/manifest directory changes

The MultiThread work set an awkward separation between the Manifest class, constructed optionally in a WebWorker in which case it is never used in main thread, and the IManifestMetadata object that is used in its place on the main thread when a WebWorker environment is set-up.

To make it clearer that the Manifest class is not to be expected everywhere, I moved class definitions deeper in src/manifest/classes (instead of just accessible in src/manifest) and only now exports types (named like the class but prefixed by I, like IManifest, IPeriod and so on) through src/manifest. This last part was added for places where classes where imported just to define a type.

All this was added to better communicate through import paths that the actual class should very rarely be relied on, though it is still awkward and not hyper clear either so I'm not too happy with the result.

import type are enforced through our linter

We now enforce through the linter the mention of type when importing TypeScript types and interfaces.

This is just to make it clearer to both humans and tools of which import is going to have an influence into the final bundle, and which are "only" here for checks at compile-time.

Enforcing eqeqeq linter rule

Previously, we had an exception to allow the usage of double equals when it was for null (e.g. a == null / a != null) as it was a shortcut for checking the equality to both null and undefined which is a generally frequent need in JavaScript.

However, we found that the trick was not known by everyone and thus we could raise code readability by checking more explicitly for both situations, by for example relying on our isNullOrUndefined util instead.

I now chose to completely enforce the linting rule which forbids double equals, even for that case.

PlaybackObserver moved to src/playback_observer

The PlaybackObserver, now named MediaElementPlaybackObserver, has been moved from src/core/api/playback_observer to src/playback_observer. This is because the concept of playback observations need to be performed by both the main_thread and the core code.

TODO: Rely on prettier

We've finally decided to take this occasion to rely on prettier for all compatible code in the project (demo, tests, source code, documentation, scripts). I will do it at the end once we are ready with everything else in this PR.

@peaBerberian peaBerberian changed the title [WIP] v4 code reorganizing [WIP] v4 code reorganization Jan 25, 2024
@peaBerberian peaBerberian force-pushed the misc/v4-dir-refacto branch 4 times, most recently from 58c80da to 1341878 Compare January 26, 2024 10:18
peaBerberian added a commit that referenced this pull request Jan 26, 2024
Root issue
----------

While working on code refactoring for better taking into account the new
potentially multithread nature of the RxPlayer code (with some files
only running in a WebWorker environment and others only running in a
main thread environment), we recently refactored our file hierarchy
(#1365) to better reflect that new situation. The idea is to make
RxPlayer developpers more aware of what code is intended to run where.

In that work, we had a remaining issue concerning the
`PlaybackObserver`.
This is the part of the code that is monitoring and advertising playback
conditions to the rest of the RxPlayer code. Most core RxPlayer modules
rely on it, in both main thread and WebWorker environments.

The root issue is that the `PlaybackObserver` is a class and thus cannot
be easily transmitted in-between environments (as the main thread and
WebWorker only exchanges between one another through `postMessage`
calls, which follows some rules preventing from doing that).

As such, and only on a multithreaded scenario, the RxPlayer is
serializing in some way the constructed source PlaybackObserver in the
main thread to reconstruct one (the `WorkerPlaybackObserver`) on the
worker.

Because a whole complex PlaybackObserver-compatible structure has to
both be constructed in the main thread and in the worker (yet only the
main thread can act as the "true" source one, because the media element
can only be accessed in main thread), we were asking ourselves where
should we put the common utils (required by both the main thread and
worker) needed to construct one (like the `ObservationPosition` class
and the `generateReadOnlyObserver` util).

Solution 1
----------

This is a first solution proposal, which moves the `PlaybackObserver`
directory outside of the `main_thread` and `core` directories. Instead,
its code is now directly in `src/playback_observer`.

This solution takes inspiration from the `src/mse` directory, which also
exports both:

  1. files intended to be imported when MSE API are present in the
     current environment (when in main thread or when in a WebWorker
     with the MSE-in-worker feature) and

  2. files intended to be imported in environments without MSE.

For example the `src/mse/main_media_source_interface.ts` should __ONLY__
be imported in environments with MSE capabilities. If you do not, you
should import `src/mse/worker_media_source_interface.ts`.

Likewise, I here added a
`src/playback_observer/media_element_playback_observer.ts` file exporting
a `MediaElementPlaybackObserver` structure (new name of the
`PlaybackObserver`) which can only be imported in environements where the
media element is available (so, only on main thread) and a
`src/playback_observer/worker_playback_observer.ts` file which should only
be imported in other environments.

Doing this allows to easily share common utils, in a
`src/playback_observer/utils` directory, without involving the rest of
the RxPlayer code.

Result
------

I'm quite happy with the result, though I get it may seem weird to have
a complex core frequently-running logic part directly in `src` (and not
in `main_thread` or `core` as was the norm) - though it is also the case
of directories like `mse` or `transports`.

RxPlayer code very rarely imported files inside other directories (which
it does here with paths like
`../playback_observer/media_element_playback_observer`) as a way to
push better modularization. Though here it may seem like a feature
because its unusual-ness forces the developper to double check if this
is the right file that is imported.
peaBerberian added a commit that referenced this pull request Jan 26, 2024
Root issue
----------

While working on code refactoring for better taking into account the new
potentially multithread nature of the RxPlayer code (with some files only
running in a WebWorker environment and others only running in a main
thread environment), we recently refactored our file hierarchy (#1365) to
better reflect that new situation. The idea is to make RxPlayer
developpers more aware of what code is intended to run where.

In that work, we had a remaining issue concerning the `PlaybackObserver`.
This is the part of the code that is monitoring and advertising playback
conditions to the rest of the RxPlayer code. Most core RxPlayer modules
rely on it, in both main thread and WebWorker environments.

The root issue is that the `PlaybackObserver` is a class and thus cannot
be easily transmitted in-between environments (as the main thread and
WebWorker only exchanges between one another through `postMessage`
calls, which follows some rules preventing from doing that).

As such, and only on a multithreaded scenario, the RxPlayer is serializing
in some way the constructed source PlaybackObserver in the main thread to
reconstruct one (the `WorkerPlaybackObserver`) on the worker.

Because a whole complex PlaybackObserver-compatible structure has to both
be constructed in the main thread and in the worker (yet only the main
thread can act as the "true" source one, because the media element can
only be accessed in main thread), we were asking ourselves where should
we put the common utils (required by both the main thread and worker)
needed to construct one (like the `ObservationPosition` class and the
`generateReadOnlyObserver` util).

Solution 1
----------

This is the second solution (after #1366), which only moves utils common
to both the WebWorker's PlaybackObserver and the main thread's
PlaybackObserver into the `src/core/main/common/` directory - just like
`ContentInitializer` utils in monothreaded mode.

In a way, this solution repeats the same solution found for
`ContentInitializer` utils - which are in a different place when ran in
monothreaded mode (where the utils is imported by the
`src/main_thread/init` logic) or ran in multithreaded mode (where the
utils imported by the `src/core/main/worker` logic).

Result
------

I will admit that I'm less a fan of this solution than #1366, as the
`src/core/main/common` feels like a hack in any scenario it is used.

There is also the fact that types exported through that path need to be
re-exported through a more accessible path (usually
src/main_thread/types`) to simplify import paths in the project.

Thoughts?
Root issue
----------

While working on code refactoring for better taking into account the new
potentially multithread nature of the RxPlayer code (with some files
only running in a WebWorker environment and others only running in a
main thread environment), we recently refactored our file hierarchy
(#1365) to better reflect that new situation. The idea is to make
RxPlayer developpers more aware of what code is intended to run where.

In that work, we had a remaining issue concerning the
`PlaybackObserver`.
This is the part of the code that is monitoring and advertising playback
conditions to the rest of the RxPlayer code. Most core RxPlayer modules
rely on it, in both main thread and WebWorker environments.

The root issue is that the `PlaybackObserver` is a class and thus cannot
be easily transmitted in-between environments (as the main thread and
WebWorker only exchanges between one another through `postMessage`
calls, which follows some rules preventing from doing that).

As such, and only on a multithreaded scenario, the RxPlayer is
serializing in some way the constructed source PlaybackObserver in the
main thread to reconstruct one (the `WorkerPlaybackObserver`) on the
worker.

Because a whole complex PlaybackObserver-compatible structure has to
both be constructed in the main thread and in the worker (yet only the
main thread can act as the "true" source one, because the media element
can only be accessed in main thread), we were asking ourselves where
should we put the common utils (required by both the main thread and
worker) needed to construct one (like the `ObservationPosition` class
and the `generateReadOnlyObserver` util).

Solution 1
----------

This is a first solution proposal, which moves the `PlaybackObserver`
directory outside of the `main_thread` and `core` directories. Instead,
its code is now directly in `src/playback_observer`.

This solution takes inspiration from the `src/mse` directory, which also
exports both:

  1. files intended to be imported when MSE API are present in the
     current environment (when in main thread or when in a WebWorker
     with the MSE-in-worker feature) and

  2. files intended to be imported in environments without MSE.

For example the `src/mse/main_media_source_interface.ts` should __ONLY__
be imported in environments with MSE capabilities. If you do not, you
should import `src/mse/worker_media_source_interface.ts`.

Likewise, I here added a
`src/playback_observer/media_element_playback_observer.ts` file exporting
a `MediaElementPlaybackObserver` structure (new name of the
`PlaybackObserver`) which can only be imported in environements where the
media element is available (so, only on main thread) and a
`src/playback_observer/worker_playback_observer.ts` file which should only
be imported in other environments.

Doing this allows to easily share common utils, in a
`src/playback_observer/utils` directory, without involving the rest of
the RxPlayer code.

Result
------

I'm quite happy with the result, though I get it may seem weird to have
a complex core frequently-running logic part directly in `src` (and not
in `main_thread` or `core` as was the norm) - though it is also the case
of directories like `mse` or `transports`.

RxPlayer code very rarely imported files inside other directories (which
it does here with paths like
`../playback_observer/media_element_playback_observer`) as a way to
push better modularization. Though here it may seem like a feature
because its unusual-ness forces the developper to double check if this
is the right file that is imported.
@peaBerberian peaBerberian merged commit 6252437 into dev Jan 31, 2024
4 checks passed
peaBerberian added a commit that referenced this pull request Jan 31, 2024
Root issue
----------

While working on code refactoring for better taking into account the new
potentially multithread nature of the RxPlayer code (with some files
only running in a WebWorker environment and others only running in a
main thread environment), we recently refactored our file hierarchy
(#1365) to better reflect that new situation. The idea is to make
RxPlayer developpers more aware of what code is intended to run where.

In that work, we had a remaining issue concerning the
`PlaybackObserver`.
This is the part of the code that is monitoring and advertising playback
conditions to the rest of the RxPlayer code. Most core RxPlayer modules
rely on it, in both main thread and WebWorker environments.

The root issue is that the `PlaybackObserver` is a class and thus cannot
be easily transmitted in-between environments (as the main thread and
WebWorker only exchanges between one another through `postMessage`
calls, which follows some rules preventing from doing that).

As such, and only on a multithreaded scenario, the RxPlayer is
serializing in some way the constructed source PlaybackObserver in the
main thread to reconstruct one (the `WorkerPlaybackObserver`) on the
worker.

Because a whole complex PlaybackObserver-compatible structure has to
both be constructed in the main thread and in the worker (yet only the
main thread can act as the "true" source one, because the media element
can only be accessed in main thread), we were asking ourselves where
should we put the common utils (required by both the main thread and
worker) needed to construct one (like the `ObservationPosition` class
and the `generateReadOnlyObserver` util).

Solution 1
----------

This is a first solution proposal, which moves the `PlaybackObserver`
directory outside of the `main_thread` and `core` directories. Instead,
its code is now directly in `src/playback_observer`.

This solution takes inspiration from the `src/mse` directory, which also
exports both:

  1. files intended to be imported when MSE API are present in the
     current environment (when in main thread or when in a WebWorker
     with the MSE-in-worker feature) and

  2. files intended to be imported in environments without MSE.

For example the `src/mse/main_media_source_interface.ts` should __ONLY__
be imported in environments with MSE capabilities. If you do not, you
should import `src/mse/worker_media_source_interface.ts`.

Likewise, I here added a
`src/playback_observer/media_element_playback_observer.ts` file exporting
a `MediaElementPlaybackObserver` structure (new name of the
`PlaybackObserver`) which can only be imported in environements where the
media element is available (so, only on main thread) and a
`src/playback_observer/worker_playback_observer.ts` file which should only
be imported in other environments.

Doing this allows to easily share common utils, in a
`src/playback_observer/utils` directory, without involving the rest of
the RxPlayer code.

Result
------

I'm quite happy with the result, though I get it may seem weird to have
a complex core frequently-running logic part directly in `src` (and not
in `main_thread` or `core` as was the norm) - though it is also the case
of directories like `mse` or `transports`.

RxPlayer code very rarely imported files inside other directories (which
it does here with paths like
`../playback_observer/media_element_playback_observer`) as a way to
push better modularization. Though here it may seem like a feature
because its unusual-ness forces the developper to double check if this
is the right file that is imported.
peaBerberian added a commit that referenced this pull request Feb 5, 2024
Root issue
----------

While working on code refactoring for better taking into account the new
potentially multithread nature of the RxPlayer code (with some files
only running in a WebWorker environment and others only running in a
main thread environment), we recently refactored our file hierarchy
(#1365) to better reflect that new situation. The idea is to make
RxPlayer developpers more aware of what code is intended to run where.

In that work, we had a remaining issue concerning the
`PlaybackObserver`.
This is the part of the code that is monitoring and advertising playback
conditions to the rest of the RxPlayer code. Most core RxPlayer modules
rely on it, in both main thread and WebWorker environments.

The root issue is that the `PlaybackObserver` is a class and thus cannot
be easily transmitted in-between environments (as the main thread and
WebWorker only exchanges between one another through `postMessage`
calls, which follows some rules preventing from doing that).

As such, and only on a multithreaded scenario, the RxPlayer is
serializing in some way the constructed source PlaybackObserver in the
main thread to reconstruct one (the `WorkerPlaybackObserver`) on the
worker.

Because a whole complex PlaybackObserver-compatible structure has to
both be constructed in the main thread and in the worker (yet only the
main thread can act as the "true" source one, because the media element
can only be accessed in main thread), we were asking ourselves where
should we put the common utils (required by both the main thread and
worker) needed to construct one (like the `ObservationPosition` class
and the `generateReadOnlyObserver` util).

Solution 1
----------

This is a first solution proposal, which moves the `PlaybackObserver`
directory outside of the `main_thread` and `core` directories. Instead,
its code is now directly in `src/playback_observer`.

This solution takes inspiration from the `src/mse` directory, which also
exports both:

  1. files intended to be imported when MSE API are present in the
     current environment (when in main thread or when in a WebWorker
     with the MSE-in-worker feature) and

  2. files intended to be imported in environments without MSE.

For example the `src/mse/main_media_source_interface.ts` should __ONLY__
be imported in environments with MSE capabilities. If you do not, you
should import `src/mse/worker_media_source_interface.ts`.

Likewise, I here added a
`src/playback_observer/media_element_playback_observer.ts` file exporting
a `MediaElementPlaybackObserver` structure (new name of the
`PlaybackObserver`) which can only be imported in environements where the
media element is available (so, only on main thread) and a
`src/playback_observer/worker_playback_observer.ts` file which should only
be imported in other environments.

Doing this allows to easily share common utils, in a
`src/playback_observer/utils` directory, without involving the rest of
the RxPlayer code.

Result
------

I'm quite happy with the result, though I get it may seem weird to have
a complex core frequently-running logic part directly in `src` (and not
in `main_thread` or `core` as was the norm) - though it is also the case
of directories like `mse` or `transports`.

RxPlayer code very rarely imported files inside other directories (which
it does here with paths like
`../playback_observer/media_element_playback_observer`) as a way to
push better modularization. Though here it may seem like a feature
because its unusual-ness forces the developper to double check if this
is the right file that is imported.
peaBerberian added a commit that referenced this pull request Feb 5, 2024
Root issue
----------

While working on code refactoring for better taking into account the new
potentially multithread nature of the RxPlayer code (with some files
only running in a WebWorker environment and others only running in a
main thread environment), we recently refactored our file hierarchy
(#1365) to better reflect that new situation. The idea is to make
RxPlayer developpers more aware of what code is intended to run where.

In that work, we had a remaining issue concerning the
`PlaybackObserver`.
This is the part of the code that is monitoring and advertising playback
conditions to the rest of the RxPlayer code. Most core RxPlayer modules
rely on it, in both main thread and WebWorker environments.

The root issue is that the `PlaybackObserver` is a class and thus cannot
be easily transmitted in-between environments (as the main thread and
WebWorker only exchanges between one another through `postMessage`
calls, which follows some rules preventing from doing that).

As such, and only on a multithreaded scenario, the RxPlayer is
serializing in some way the constructed source PlaybackObserver in the
main thread to reconstruct one (the `WorkerPlaybackObserver`) on the
worker.

Because a whole complex PlaybackObserver-compatible structure has to
both be constructed in the main thread and in the worker (yet only the
main thread can act as the "true" source one, because the media element
can only be accessed in main thread), we were asking ourselves where
should we put the common utils (required by both the main thread and
worker) needed to construct one (like the `ObservationPosition` class
and the `generateReadOnlyObserver` util).

Solution 1
----------

This is a first solution proposal, which moves the `PlaybackObserver`
directory outside of the `main_thread` and `core` directories. Instead,
its code is now directly in `src/playback_observer`.

This solution takes inspiration from the `src/mse` directory, which also
exports both:

  1. files intended to be imported when MSE API are present in the
     current environment (when in main thread or when in a WebWorker
     with the MSE-in-worker feature) and

  2. files intended to be imported in environments without MSE.

For example the `src/mse/main_media_source_interface.ts` should __ONLY__
be imported in environments with MSE capabilities. If you do not, you
should import `src/mse/worker_media_source_interface.ts`.

Likewise, I here added a
`src/playback_observer/media_element_playback_observer.ts` file exporting
a `MediaElementPlaybackObserver` structure (new name of the
`PlaybackObserver`) which can only be imported in environements where the
media element is available (so, only on main thread) and a
`src/playback_observer/worker_playback_observer.ts` file which should only
be imported in other environments.

Doing this allows to easily share common utils, in a
`src/playback_observer/utils` directory, without involving the rest of
the RxPlayer code.

Result
------

I'm quite happy with the result, though I get it may seem weird to have
a complex core frequently-running logic part directly in `src` (and not
in `main_thread` or `core` as was the norm) - though it is also the case
of directories like `mse` or `transports`.

RxPlayer code very rarely imported files inside other directories (which
it does here with paths like
`../playback_observer/media_element_playback_observer`) as a way to
push better modularization. Though here it may seem like a feature
because its unusual-ness forces the developper to double check if this
is the right file that is imported.
peaBerberian added a commit that referenced this pull request Feb 5, 2024
Root issue
----------

While working on code refactoring for better taking into account the new
potentially multithread nature of the RxPlayer code (with some files
only running in a WebWorker environment and others only running in a
main thread environment), we recently refactored our file hierarchy
(#1365) to better reflect that new situation. The idea is to make
RxPlayer developpers more aware of what code is intended to run where.

In that work, we had a remaining issue concerning the
`PlaybackObserver`.
This is the part of the code that is monitoring and advertising playback
conditions to the rest of the RxPlayer code. Most core RxPlayer modules
rely on it, in both main thread and WebWorker environments.

The root issue is that the `PlaybackObserver` is a class and thus cannot
be easily transmitted in-between environments (as the main thread and
WebWorker only exchanges between one another through `postMessage`
calls, which follows some rules preventing from doing that).

As such, and only on a multithreaded scenario, the RxPlayer is
serializing in some way the constructed source PlaybackObserver in the
main thread to reconstruct one (the `WorkerPlaybackObserver`) on the
worker.

Because a whole complex PlaybackObserver-compatible structure has to
both be constructed in the main thread and in the worker (yet only the
main thread can act as the "true" source one, because the media element
can only be accessed in main thread), we were asking ourselves where
should we put the common utils (required by both the main thread and
worker) needed to construct one (like the `ObservationPosition` class
and the `generateReadOnlyObserver` util).

Solution 1
----------

This is a first solution proposal, which moves the `PlaybackObserver`
directory outside of the `main_thread` and `core` directories. Instead,
its code is now directly in `src/playback_observer`.

This solution takes inspiration from the `src/mse` directory, which also
exports both:

  1. files intended to be imported when MSE API are present in the
     current environment (when in main thread or when in a WebWorker
     with the MSE-in-worker feature) and

  2. files intended to be imported in environments without MSE.

For example the `src/mse/main_media_source_interface.ts` should __ONLY__
be imported in environments with MSE capabilities. If you do not, you
should import `src/mse/worker_media_source_interface.ts`.

Likewise, I here added a
`src/playback_observer/media_element_playback_observer.ts` file exporting
a `MediaElementPlaybackObserver` structure (new name of the
`PlaybackObserver`) which can only be imported in environements where the
media element is available (so, only on main thread) and a
`src/playback_observer/worker_playback_observer.ts` file which should only
be imported in other environments.

Doing this allows to easily share common utils, in a
`src/playback_observer/utils` directory, without involving the rest of
the RxPlayer code.

Result
------

I'm quite happy with the result, though I get it may seem weird to have
a complex core frequently-running logic part directly in `src` (and not
in `main_thread` or `core` as was the norm) - though it is also the case
of directories like `mse` or `transports`.

RxPlayer code very rarely imported files inside other directories (which
it does here with paths like
`../playback_observer/media_element_playback_observer`) as a way to
push better modularization. Though here it may seem like a feature
because its unusual-ness forces the developper to double check if this
is the right file that is imported.
peaBerberian added a commit that referenced this pull request Feb 5, 2024
Root issue
----------

While working on code refactoring for better taking into account the new
potentially multithread nature of the RxPlayer code (with some files
only running in a WebWorker environment and others only running in a
main thread environment), we recently refactored our file hierarchy
(#1365) to better reflect that new situation. The idea is to make
RxPlayer developpers more aware of what code is intended to run where.

In that work, we had a remaining issue concerning the
`PlaybackObserver`.
This is the part of the code that is monitoring and advertising playback
conditions to the rest of the RxPlayer code. Most core RxPlayer modules
rely on it, in both main thread and WebWorker environments.

The root issue is that the `PlaybackObserver` is a class and thus cannot
be easily transmitted in-between environments (as the main thread and
WebWorker only exchanges between one another through `postMessage`
calls, which follows some rules preventing from doing that).

As such, and only on a multithreaded scenario, the RxPlayer is
serializing in some way the constructed source PlaybackObserver in the
main thread to reconstruct one (the `WorkerPlaybackObserver`) on the
worker.

Because a whole complex PlaybackObserver-compatible structure has to
both be constructed in the main thread and in the worker (yet only the
main thread can act as the "true" source one, because the media element
can only be accessed in main thread), we were asking ourselves where
should we put the common utils (required by both the main thread and
worker) needed to construct one (like the `ObservationPosition` class
and the `generateReadOnlyObserver` util).

Solution 1
----------

This is a first solution proposal, which moves the `PlaybackObserver`
directory outside of the `main_thread` and `core` directories. Instead,
its code is now directly in `src/playback_observer`.

This solution takes inspiration from the `src/mse` directory, which also
exports both:

  1. files intended to be imported when MSE API are present in the
     current environment (when in main thread or when in a WebWorker
     with the MSE-in-worker feature) and

  2. files intended to be imported in environments without MSE.

For example the `src/mse/main_media_source_interface.ts` should __ONLY__
be imported in environments with MSE capabilities. If you do not, you
should import `src/mse/worker_media_source_interface.ts`.

Likewise, I here added a
`src/playback_observer/media_element_playback_observer.ts` file exporting
a `MediaElementPlaybackObserver` structure (new name of the
`PlaybackObserver`) which can only be imported in environements where the
media element is available (so, only on main thread) and a
`src/playback_observer/worker_playback_observer.ts` file which should only
be imported in other environments.

Doing this allows to easily share common utils, in a
`src/playback_observer/utils` directory, without involving the rest of
the RxPlayer code.

Result
------

I'm quite happy with the result, though I get it may seem weird to have
a complex core frequently-running logic part directly in `src` (and not
in `main_thread` or `core` as was the norm) - though it is also the case
of directories like `mse` or `transports`.

RxPlayer code very rarely imported files inside other directories (which
it does here with paths like
`../playback_observer/media_element_playback_observer`) as a way to
push better modularization. Though here it may seem like a feature
because its unusual-ness forces the developper to double check if this
is the right file that is imported.
@peaBerberian peaBerberian added this to the 4.1.0 milestone Feb 5, 2024
peaBerberian added a commit that referenced this pull request Feb 20, 2024
Root issue
----------

While working on code refactoring for better taking into account the new
potentially multithread nature of the RxPlayer code (with some files
only running in a WebWorker environment and others only running in a
main thread environment), we recently refactored our file hierarchy
(#1365) to better reflect that new situation. The idea is to make
RxPlayer developpers more aware of what code is intended to run where.

In that work, we had a remaining issue concerning the
`PlaybackObserver`.
This is the part of the code that is monitoring and advertising playback
conditions to the rest of the RxPlayer code. Most core RxPlayer modules
rely on it, in both main thread and WebWorker environments.

The root issue is that the `PlaybackObserver` is a class and thus cannot
be easily transmitted in-between environments (as the main thread and
WebWorker only exchanges between one another through `postMessage`
calls, which follows some rules preventing from doing that).

As such, and only on a multithreaded scenario, the RxPlayer is
serializing in some way the constructed source PlaybackObserver in the
main thread to reconstruct one (the `WorkerPlaybackObserver`) on the
worker.

Because a whole complex PlaybackObserver-compatible structure has to
both be constructed in the main thread and in the worker (yet only the
main thread can act as the "true" source one, because the media element
can only be accessed in main thread), we were asking ourselves where
should we put the common utils (required by both the main thread and
worker) needed to construct one (like the `ObservationPosition` class
and the `generateReadOnlyObserver` util).

Solution 1
----------

This is a first solution proposal, which moves the `PlaybackObserver`
directory outside of the `main_thread` and `core` directories. Instead,
its code is now directly in `src/playback_observer`.

This solution takes inspiration from the `src/mse` directory, which also
exports both:

  1. files intended to be imported when MSE API are present in the
     current environment (when in main thread or when in a WebWorker
     with the MSE-in-worker feature) and

  2. files intended to be imported in environments without MSE.

For example the `src/mse/main_media_source_interface.ts` should __ONLY__
be imported in environments with MSE capabilities. If you do not, you
should import `src/mse/worker_media_source_interface.ts`.

Likewise, I here added a
`src/playback_observer/media_element_playback_observer.ts` file exporting
a `MediaElementPlaybackObserver` structure (new name of the
`PlaybackObserver`) which can only be imported in environements where the
media element is available (so, only on main thread) and a
`src/playback_observer/worker_playback_observer.ts` file which should only
be imported in other environments.

Doing this allows to easily share common utils, in a
`src/playback_observer/utils` directory, without involving the rest of
the RxPlayer code.

Result
------

I'm quite happy with the result, though I get it may seem weird to have
a complex core frequently-running logic part directly in `src` (and not
in `main_thread` or `core` as was the norm) - though it is also the case
of directories like `mse` or `transports`.

RxPlayer code very rarely imported files inside other directories (which
it does here with paths like
`../playback_observer/media_element_playback_observer`) as a way to
push better modularization. Though here it may seem like a feature
because its unusual-ness forces the developper to double check if this
is the right file that is imported.
peaBerberian added a commit that referenced this pull request Feb 20, 2024
Root issue
----------

While working on code refactoring for better taking into account the new
potentially multithread nature of the RxPlayer code (with some files
only running in a WebWorker environment and others only running in a
main thread environment), we recently refactored our file hierarchy
(#1365) to better reflect that new situation. The idea is to make
RxPlayer developpers more aware of what code is intended to run where.

In that work, we had a remaining issue concerning the
`PlaybackObserver`.
This is the part of the code that is monitoring and advertising playback
conditions to the rest of the RxPlayer code. Most core RxPlayer modules
rely on it, in both main thread and WebWorker environments.

The root issue is that the `PlaybackObserver` is a class and thus cannot
be easily transmitted in-between environments (as the main thread and
WebWorker only exchanges between one another through `postMessage`
calls, which follows some rules preventing from doing that).

As such, and only on a multithreaded scenario, the RxPlayer is
serializing in some way the constructed source PlaybackObserver in the
main thread to reconstruct one (the `WorkerPlaybackObserver`) on the
worker.

Because a whole complex PlaybackObserver-compatible structure has to
both be constructed in the main thread and in the worker (yet only the
main thread can act as the "true" source one, because the media element
can only be accessed in main thread), we were asking ourselves where
should we put the common utils (required by both the main thread and
worker) needed to construct one (like the `ObservationPosition` class
and the `generateReadOnlyObserver` util).

Solution 1
----------

This is a first solution proposal, which moves the `PlaybackObserver`
directory outside of the `main_thread` and `core` directories. Instead,
its code is now directly in `src/playback_observer`.

This solution takes inspiration from the `src/mse` directory, which also
exports both:

  1. files intended to be imported when MSE API are present in the
     current environment (when in main thread or when in a WebWorker
     with the MSE-in-worker feature) and

  2. files intended to be imported in environments without MSE.

For example the `src/mse/main_media_source_interface.ts` should __ONLY__
be imported in environments with MSE capabilities. If you do not, you
should import `src/mse/worker_media_source_interface.ts`.

Likewise, I here added a
`src/playback_observer/media_element_playback_observer.ts` file exporting
a `MediaElementPlaybackObserver` structure (new name of the
`PlaybackObserver`) which can only be imported in environements where the
media element is available (so, only on main thread) and a
`src/playback_observer/worker_playback_observer.ts` file which should only
be imported in other environments.

Doing this allows to easily share common utils, in a
`src/playback_observer/utils` directory, without involving the rest of
the RxPlayer code.

Result
------

I'm quite happy with the result, though I get it may seem weird to have
a complex core frequently-running logic part directly in `src` (and not
in `main_thread` or `core` as was the norm) - though it is also the case
of directories like `mse` or `transports`.

RxPlayer code very rarely imported files inside other directories (which
it does here with paths like
`../playback_observer/media_element_playback_observer`) as a way to
push better modularization. Though here it may seem like a feature
because its unusual-ness forces the developper to double check if this
is the right file that is imported.
@peaBerberian peaBerberian mentioned this pull request Jun 13, 2024
peaBerberian added a commit that referenced this pull request Jun 13, 2024
Root issue
----------

While working on code refactoring for better taking into account the new
potentially multithread nature of the RxPlayer code (with some files
only running in a WebWorker environment and others only running in a
main thread environment), we recently refactored our file hierarchy
(#1365) to better reflect that new situation. The idea is to make
RxPlayer developpers more aware of what code is intended to run where.

In that work, we had a remaining issue concerning the
`PlaybackObserver`.
This is the part of the code that is monitoring and advertising playback
conditions to the rest of the RxPlayer code. Most core RxPlayer modules
rely on it, in both main thread and WebWorker environments.

The root issue is that the `PlaybackObserver` is a class and thus cannot
be easily transmitted in-between environments (as the main thread and
WebWorker only exchanges between one another through `postMessage`
calls, which follows some rules preventing from doing that).

As such, and only on a multithreaded scenario, the RxPlayer is
serializing in some way the constructed source PlaybackObserver in the
main thread to reconstruct one (the `WorkerPlaybackObserver`) on the
worker.

Because a whole complex PlaybackObserver-compatible structure has to
both be constructed in the main thread and in the worker (yet only the
main thread can act as the "true" source one, because the media element
can only be accessed in main thread), we were asking ourselves where
should we put the common utils (required by both the main thread and
worker) needed to construct one (like the `ObservationPosition` class
and the `generateReadOnlyObserver` util).

Solution 1
----------

This is a first solution proposal, which moves the `PlaybackObserver`
directory outside of the `main_thread` and `core` directories. Instead,
its code is now directly in `src/playback_observer`.

This solution takes inspiration from the `src/mse` directory, which also
exports both:

  1. files intended to be imported when MSE API are present in the
     current environment (when in main thread or when in a WebWorker
     with the MSE-in-worker feature) and

  2. files intended to be imported in environments without MSE.

For example the `src/mse/main_media_source_interface.ts` should __ONLY__
be imported in environments with MSE capabilities. If you do not, you
should import `src/mse/worker_media_source_interface.ts`.

Likewise, I here added a
`src/playback_observer/media_element_playback_observer.ts` file exporting
a `MediaElementPlaybackObserver` structure (new name of the
`PlaybackObserver`) which can only be imported in environements where the
media element is available (so, only on main thread) and a
`src/playback_observer/worker_playback_observer.ts` file which should only
be imported in other environments.

Doing this allows to easily share common utils, in a
`src/playback_observer/utils` directory, without involving the rest of
the RxPlayer code.

Result
------

I'm quite happy with the result, though I get it may seem weird to have
a complex core frequently-running logic part directly in `src` (and not
in `main_thread` or `core` as was the norm) - though it is also the case
of directories like `mse` or `transports`.

RxPlayer code very rarely imported files inside other directories (which
it does here with paths like
`../playback_observer/media_element_playback_observer`) as a way to
push better modularization. Though here it may seem like a feature
because its unusual-ness forces the developper to double check if this
is the right file that is imported.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants