The Audio.js setRef callback does not behave like react ref callback
in that the former will not have fired before componentDidMount
but the later will have. So for audio output preview, trying to set
sink id on mount will no-op because it does not have a ref yet to
Audio.js, possibly leading to audio output previews playing on
the default speaker device. This generally has not been a user
visible problem due to coincidence; other re-renders necessary
by the parent of audio output preview will have triggered
componentDidUpdates on the audio out preview, which would then
set the sink id on the Audio.js ref it should have received
by then.
Searching for a device (id) by label alone can result in
false results when devices share labels, such as a mic
and speaker having the same label. To prevent such,
specify the device kind to be found instead of iterating
over all device kinds.
Devices of different kinds can have the same id, such as speaker
and mic both being default. Using id only can then lead to
incorrectly setting device descriptions in the current devices
object.
Using anything non-serializable for action types is discouraged:
https://redux.js.org/faq/actions#actions
In fact, this is the Flow definition for dispatching actions:
declare export type DispatchAPI<A> = (action: A) => A;
declare export type Dispatch<A: { type: $Subtype<string> }> = DispatchAPI<A>;
Note how the `type` field is defined as a subtype of string, which Symbol isn’t.
For the most part the changes are taking the "static propTypes" declaration off
of components and declaring them as Flow types. Sometimes to support flow some
method signatures had to be added. There are some exceptions in which more had
to be done to tame the beast:
- AbstractVideoTrack: put in additional truthy checks for videoTrack.
- Video: add truthy checks for the _videoElement ref.
- shouldRenderVideoTrack function: Some component could pass null for the
videoTrack argument and Flow wanted that called out explicitly.
- DisplayName: Add a truthy check for the input ref before acting on it.
- NumbersList: Move array checks inline for Flow to comprehend array methods
could be called. Add type checks in the Object.entries loop as the value is
assumed to be a mixed type by Flow.
- AbstractToolbarButton: add additional truthy check for passed in type.
There are (at least) two changes that are breaking:
- defaultTab is gone
- The re-rendering logic looks to have been re-written so that
passing in a new array of tabs causes a re-render, which can
reset the currently selected tab.
The fixes involved removing defaultTab from each tab configuration,
as it is no longer respected anyway. Also, instead of letting Tabs
be uncontrolled and allowing it to set its own selected, which
would result in the first tab automatically being selected on
Tabs re-render, use Tabs a controlled prop to dicate which
tab is selected; this is accomplished by specifying a selected
prop.
* feat(welcome-page): be able to open settings dialog
- Create a getter for getting a settings tab's props so the device
selection tab can get updated available devices.
- Be able to call a function from a tab after it has mounted. This is
used for device selection to essentially call enumerateDevices on
the welcome page so the device selectors are populated.
- Remove event UIEvents.AUDIO_OUTPUT_DEVICE_CHANGED. Instead directly call
setAudioOutputDeviceId where possible.
- Fix initialization of the audioOutputDeviceId in settings by defaulting
the audio output device to the one set in settings.
* squash: updateAvailableDevices -> getAvailableDevices, add comment for propsUpdateFunction
Unfortunately, as the Jitsi Meet development evolved the routing mechanism
became more complex and thre logic ended up spread across multiple parts of the
codebase, which made it hard to follow and extend.
This change aims to fix that by rewriting the routing logic and centralizing it
in (pretty much) a single place, with no implicit inter-dependencies.
In order to arrive there, however, some extra changes were needed, which were
not caught early enough and are thus part of this change:
- JitsiMeetJS initialization is now synchronous: there is nothing async about
it, and the only async requirement (Temasys support) was lifted. See [0].
- WebRTC support can be detected early: building on top of the above, WebRTC
support can now be detected immediately, so take advantage of this to simplify
how we handle unsupported browsers. See [0].
The new router takes decissions based on the Redux state at the time of
invocation. A route can be represented by either a component or a URl reference,
with the latter taking precedence. On mobile, obviously, there is no concept of
URL reference so routing is based solely on components.
[0]: https://github.com/jitsi/lib-jitsi-meet/pull/779
* feat(settings): setting dialog
- Move device selection, profile edit, language select, moderator
options, and server auth into one modal with tabs.
- Remove side panel profile and settings and logic used to update
them.
- Pipe server auth status into redux to display in the settings
dialog.
- Change filmstrip only device selection popup to use the new
stateless settings dialog component.
* squash: do not show profile tab if not guest
* squash: profile button not clickable if no profile to show
* squash: nits
* ref: Settings dialog.
AtlasKit is not fully compatible with React 16. One problem
is PropTypes will not be defined on the React object. So,
add the prop-types shim to the popup bundle.
* feat(audio-only): be able to lock a browser into capturing audio only
* squash: try to make string more clear about audio only support
* squash: final strings
ESLint 4.8.0 discovers a lot of error related to formatting. While I
tried to fix as many of them as possible, a portion of them actually go
against our coding style. In such a case, I've disabled the indent rule
which effectively leaves it as it was before ESLint 4.8.0.
Additionally, remove jshint because it's becoming a nuisance with its
lack of understanding of ES2015+.
Filmstrip only mode displays a device selection dialog that
does not have access to the redux/connect. However, the current
VideoTrack extends from AbstractVideoTrack, which assumes a
redux connection. The fix is to move video display logic into
a separate component and have device selection use that, while
the existing VideoTrack remains connected to redux but
uses the new video display component.
* feat(local-video): convert to react
- Create a VideoTrack component for displaying a video element.
This mirrors native also having a VideoTrack component.
- The VideoTrack component does not let React update it to prevent
the video element from re-rendering, which could cause flickers
and would not work with temasys's overriding of the video element.
- VideoTrack extends AbstractVideoTrack to mirror native
implementation and to get the dispatch of the onplaying event.
- Remove the onclick handler on the video element. Honestly, I
didn't get it to work, and did not try, but it is also unnecessary
because another handler already exists on the video wrapper.
* ref(device-selection): VideoInputPreview uses VideoTrack to show video
* squash into conversion: change css selectors
* squash into conversion: mix in abstract props
* squash into conversion: change shouldComponentUpdate check
* squash: update comment about why triggerOnPlayingUpdate is used
Device selection has live previews that reuse the current local
audio and video tracks for the sake of internet explorer. This
means when the local video was muted, device selection would
show a muted message. It is preferred to show a live preview
even when muted.
The changes include:
- Passing device ids into DeviceSelectionDialog, not tracks.
- Setting default selected devices to use for live previews.
- Removing all checks in DeviceSelectionDialog involving local tracks.
- Catching and displaying errors when creating a live video preview.
AtlasKit DropdownMenu cannot be disabled, unlike Single Select.
The result is the isDisabled prop was not being honored. The
workaround is returning only the trigger element for the dropdown
and styling it to look like the dropdown is disabled. The text
for disabled device selection was changed along the way to fit
into the trigger.
AtlasKit Dropdown was recently updated to support fitting the
width of its container. However, AtlasKit Button, the trigger
element currently used for the dropdowns, does not fit the width
of AtlasKit Dropdown and stll has text overflowing out of its
button when there is an iconBefore prop passed in. Instead of
using AtlasKit Button, use a div and mimic the button look. This
allows the "button" to fit the container width and can display
ellipsized text within itself.
Instead of using AtlasKit Single-Select, use Dropdown. Dropdown
differs in that an icon can be specified for the trigger element,
whereas Single-Select currently supports icons for all elements,
and Dropdown can show all options incuding the already-selected
option.
This change does introduce the issue of the trigger element not
taking up 100% width of the parent. Supporting such would involve
overriding AtlasKit CSS. The compromise made here was to do a
generic override of max-width so the trigger elements at least
stay within the parent and aligning the trigger elements to the
right.