We are downloading code off the Internet and executing it on the user's device,
so run it sandboxed to avoid potential bad actors.
Since it's impossible to eval() safely in JS and React Native doesn't offer
something akin to Node's vm module, here we are rolling our own.
On Android it uses the Duktape JavaScript engine and on iOS the builtin
JavaScriptCore engine. The extra JS engine is *only* used for evaluating the
downloaded code and returning a JSON string which is then passed back to RN.
- use AbortController for setting the fetch timeout
- use async / await syntax for clarify
- set the default timeout to 5s (previously non-existent, aka 0)
- add ability to load but not evaluate a script
They never worked on mobile and pose an impediment for makinf config.js more
future proof. Specially if we want to move to a non-executable form of
configuration.
This adds an option to disable video autoplay that will be used mostly with maleus (our selenium-based load testing tool for testing the new bridge). Disabling video rendering lowers the resource utilisation of the selenium nodes.
Bring back the workaround introduced in afd2aea7
but removed in 21dcc41d. On conference join,
several other actions have already been fired
that try to set the large video participant
and select the participant on the bridge.
The problem is there is no conference during
these actions so the select participant
never fires. Then subsequent actions do not
fire select participant because the large
video participant has not changed.
We try to load the configuration with every room change, even when there is no
room. There is a bad (corner) case: when we have no config cached (first boot or
wiped app data). In such case the user is trapped in an infinite loop because we
require the config to show the welcome page, oh well.
Pretend we have a configuration by creating the most minimal one to at least get
to the welcome page.
Audio streams are automatically played by WebRTC and this won't change, probably
ever. There is no point in having checks and an Audio component which does
nothing.
In iOS 13 if the call is not unmuted when we report it to the system as started,
an action to unmute it is dispatched automagically. Thanks, Apple.
So, delay synchronizing the muted state until the conference is started (after
the join action). This creates a small window for de-synchronization, but it's
very short and it seems unavoidable.
This change is only applied to operating systems built by the fruit company in
Cupertino.
These provide the ability to integrate the SDK with some other application
loggers.
At the time this was written we use Timber on Android and CocoaLumberjack on iOS.
In addition to the integration capabilities, a LogBridge React Native module
provides log transports for JavaScript code, thus centralizing all logs on the
native loggers.
Will emit new 'network.info' action with the online/offline status and
extra details for native like the network type and
'isConnectionExpensive' flag.
It need not always exist, since it's created asynchronousluy on app
initiualization. Make sure we are ready for it.
I've seen backtraces because of this.
Any overrides set on interfaceConfig are not
applied on module load. As such, call to get
the value of the auto pin setting, providing
time for the bootstrapping to set overrides.
Otherwise iframe api users cannot override
the setting.
React Native doesn't define __filename nor __dirname so do it artisanally. In
addition, this helps with centralizing the configuration passed to loggers.
Mobile uses a different logic for deciding whether to show the filmstrip or not:
if there are more than 1 participants or not, and there is no way to manually
toggle it.
This commit refactors device selection (more heavily on iOS) to make it
consistent across platforms.
Due to its complexity I couldn't break out each step into separate commits,
apologies to the reviewer.
Changes made to device handling:
- speaker is always the default, regardless of the mode
- "Phone" shows as a selectable option, even in video call mode
- "Phone" is not displayed when wired headphones are present
- Shared device picker between iOS and Android
- Runtime device updates while the picker is open
It's an evolution of audio-only mode, where we also allow for receiving a remote
screen-share.
Diving deeper: this basically sets last N to 1 or 0 depending on the
availability of a screen-share.
This prevents inserting any user overridden APP_NAME
values into html. A new translation key is being used
to immediately stop non-english languages from using the
problematic string.
Also tweaked the copy to remove the "eer" and fix
some grammar.
This refactors all handling of audio-only and last N to 2 features in preparation
for "low bandwidth mode".
The main motivation to do this is that lastN is a "global" setting so it helps
to have all processing for it in a single place.
* ref(feedback): emit api feedback submitted on completion
Compared to firing the event on submission because
the submission ajax will not be completed at that
time..
* squash: update package.json
When a participant is pinned in the UI we then proceed to mark it as selected on
the JVB. This will make the participant part of the last N set and will receive
the highest (or configured highest) video quality.
Pinning a participant at the JVB level just makes sure it will be part of the
last N set.
Since only one participant can be pinned in the UI, there is no point in pinning
it at the JVB level, since selecting it already achieved the same result.
Moves getCurrentConferenceUrl method to base/connection to allow reuse.
The new location is not ideal, but looks the best based on the imports
required (trying to avoid circular dependencies).
* Moves talk while muted as a new feature.
* Adds sound notification for talk while muted.
* Reorder imports and changes the dispatch of the notification.
* Introduces sounds.js for talk while muted.
* Removes unused translations.
* Fixes using translated strings.
* Moves using latest i18next versions and stop using compatibility modes.
* Sorts i18next options.
* Fixes defaultNS used by i18next.
This is used when translating html tags with data-i18n keys as attributes, used by jQuery-Impromptu.
* ref(user-interaction): remove storing of listener
* ref(user-interaction): move browser requirement check to lib-jitsi-meet
* ref(user-interaction): no inner function for listener, use module scope
* Listens for suspend events from jitsi-power-monitor on postis channel.
* Removes duplicated type and actions.
* Moves suspendDetected state from overlay to power-monitor feature.
* fix(invite): decode the meeting name
* squash: try to make mobile join same encoded meeting name as web
* Decodes and generated texts for share and copy meeting info.
Decodes in all cases except when it contains a space, as it will generate wrong links when pasted/shared in external applications.
* Adds a notification when remote lock happens.
* Updates translations.
Removes unused strings and extracts room password to separate translation, to be able to change it when deployment uses only digits.
* Formats the conference pin when showing it.
* Removes member from translation in favour of participant.
* Updates formatting of the pin.
* Adds a notification when password is remotely removed.
Join notifications are already supressed for the local
participant, so hide the left notification. For now
the notification is not being shown on mobile to keep
the same existing behavior and because a copy change
will be needed, but will be added once batching is
implemented.
When native SDK users end a meeting the view gets disposed and detached from
React, and then the entire app gets destroyed and these errors get printed at
the error level, throwing some people off.
* Fixes inviting more than one participant.
* Shows a notification when participants are invited.
* Adds support for both .id and .user_id props for people query results.
This was hit on a corner case when ConnectionService will deny
the request to start the call. I am not sure, but it could have been
that the conference object has been disposed or closed or something
else, but the fact is that 'conference.room' was not defined and things
crashed. It is not safe to access conference's private field 'room'. It
is true JitsiConference doesn't follow the practice of marking this
field as private with the underscore '_', but it is not a public field.
* Updates kick showing who kicked us.
* Notify participants that someone was kicked.
* Shows notification to user who is remotely muted.
* Updates the notification type.
* Muted by notification for mobile.
* Moves code to react and adds the kick notifications to mobile.
* Updates lib-jitsi-meet.
* Updates start silent, turning on startWithAudioMuted and few UI tweaks.
Disabled mic unmute button and removes remote participants volume slider.
* Adds analytics for start silent.
* Removes extra semi colon.
* Updates lib-jitsi-meet and updates meeting info text.
Checking if the calendar support in the reducer is not only useless but wrong,
since we don't have access to the entire store (the calendar support is checked
in the base/config feature). If calendar support is not enabled the actions
being reduced won't be dispatched anyway, so no harm is done by removing the
check.
When the video unmute button disabled audio-only, also unmute video. This fixes
a weird case in which the user need to "unmute twice" if they were muted beofre
they enabled audio-only mode. That's ok if the audio-only button was used, but
not if the video-unmute button was used, since the expectation is to have video,
of course.
Re-structure the custom routing to split between
platforms instead of between intended route features.
This made it easier for me to understand where to
do the checks for unsupported browser after deep-linking
had been checked.
If a value is not set in localStorage then null is
returned. null should not be converted to an empty
string (via _.escape) because that will then be
stored in localStorage as the user set preference
and will keep overriding any other values set
in localStorage for the displayname.
- Use actions to notify the rest of the app that
a mic or camera error has occurred
- Use middleware to respond to those notifications
of errors by showing in-app notifications and
notifying the external api
When in a conference, try to enter PiP when pressing the back button. If this is
not possible (because it's unsupported, not enabled, etc.) fall back to the
previous behavior of simply hanging up.
This PR changes the logic for connecting / disconnecting conferences. Instead of
doing it in mount / unmount events from the Conference component, it moves the
logic to the appNavigatee action.
This fixes a regression introduced in 774c5ecd when trying to make sure the
conference terminated event is always sent.
By moving the logic to appNavigate we no longer depend on side-effects for
connecting / disconnecting, and the code should be more maintainable moving
forward.
An improvement to this is the concept of sessions, which, while not tackled
here, was taken into consideration.
For the external api to fire update events out of the iframe, it
must first be initialized within the jitsi app. Any invocations
by the app to send updates events before initialization will
cause the api to swallow the events. The chosen fix is to
initialize the api earlier so the first update of app's redux
store fires update events that the api will also fire out of
the iframe.
This change will affect current behavior in that right now
the update event of the initial set of the avatar url is
blocked, but the change will make that event fire out of the
iframe.
Currently devices set through the api are stored
as ids, and not user selected. This can cause
other existing user selected devices to take
precedence over the devices passed into the api.
By making the container 100% height and position relative, that
would cause it to overlap any static-positioned elements below it.
The 100% makes it so that any watermarks intended for the bottom
of the page show up on the bottom of the page. However, it's not
needed because watermark stylings already try to position the
watermarks at the bottom.
* Fix detecting preferred audio output.
Fixes detecting when a new output device is found and we have stored user preference of using that device.
* Does not store which is the currently open device on save.
Does not save the currently opened device when saving settings dialog, this will be done once we successfully replace the tracks to use the new devices.
* Saves opened audio device after successfully changing it.
If we do it earlier _updateAudioDeviceId is using localAudio and can store wrong value.
* Adds notification for new non preferred devices.
A notification is shown which gives an option to the user to select and use the newly plugged devices.
Adding custom button and handler for the action to the notifications.
* Changes logic to search and handle all newly added devices from array.
* Moves some utility methods to features/base/devices.
The state about currently opened devices is filtered and not stored, where we only store when user selects a device preferences.
Also allow changing input devices for Firefox when we are not in a conference.
* Prints errors in case of wrong initialization.
Not printing can masks some errors in the code.
* Allow only one Follow Me moderator in a meeting.
* Sends Follow Me state with all presences of the moderator.
This fixes an issue where the moderator sends the Follow Me state and then for example mute or unmute video (this will produce a presence without Follow Me state) and the new comers will not reflect current Follow Me state till a change of it comes.
* Changes fixing comments.
* Changes fixing comments.
Dear reader, I'm not proud at all of what you are about to read, but sometimes
life just gives you lemons, so enjoy some lemonade!
Joining a conference implies first creating the XMPP connection and then joining
the MUC. It's very possible the XMPP connection was made but there was no chance
for the conference to be created.
This patch fixes this case by artificially genrating a conference terminated
event in such case. In order to have all the necessary knowledge for this event
to be sent the connection now keeps track of the conference that runs it.
In addition, there is an even more obscure corner case: it's not impossible to
try to disconnect when there is not even a connection. This was fixed by
creating a fake disconnect event. Alas the location URL is lost at this point,
but it's better than nothing I guess.
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.
When the iFrame api is used to set a preferred audio output using
options passed into the JitsiMeetExternalAPI constructor, no logic
fires to actually change the audio output destination.
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.
* ref(display-name): do not pass in display name
The component gets the state itself from redux.
* fix(display-name): do not default name to placeholder name
The web display name component supports inline editing of
the name. Problems can occur when the displayed name
differs from the actual saved name, because participants
without a display name, including the local user, have
a different, default display name displayed. So when
editing starts, the input field is populated with the
default name. To workaround such while supporting fetching
the display name using mapStateToProps, pass in both the
name which should be shown and the name value saved in
settings.
* ref(display-name): rename methods
If user dismisses the not topmost notification the timeout will be
cleared and a new one will not be set, because the top notification
remained the same (see the if at line 90).
The docs of 'componentDidUpdate' say that it's not called for the
initial render. If the component is added to the DOM with 1 notification
already, then the update will not happen and timeout will never be set
which will effectively break the timeouts chain.
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.
* Removes unused ADD_PEOPLE_APP_NAME
* Moves deep-link header background and logo size as variables.
* Fixes more numbers page space in the header.
* Fixes left padding on deep-linking mobile page.
Consolidate all failure cases into a single one: CONFERENCE_TERMINATED. If the
conference ended gracefully no error indicator will be present, otherwise there
will be.
There is no need for AbstractApp to require some getWindowLocation function.
It's only used in one place and we even polyfill it on mobile.
Thus replace it's usage with more specific functions.
* Adds new format of phoneList service and re-design dial in numbers page.
Adds flags and country names (with translations) for the numbers if using the new format.
* Fixes tests and fixes get default number.
* Updates swagger with new format.
* Moves html back yo table.
Fixes displaying on mobile and also the tel: URI generation. The tel: URI is tested on Android and iOS and seems to work (Android was not interpreting 'p', but both seems to like ',').
* Fixes a wrong return statement.
* Small fixes.
The conference disconnection process is asynchronous which means there's
no guarantee that there will be CONFERENCE_LEFT event for the old
conference, before the next conference is joined. Because of that we can
end up with two simultaneous calls on the native side which is not
always supported. End the call on CONFERENCE_WILL_LEAVE to fix this
corner case.
* fix(large-video): do not show avatar if no url
By default the large video dominant speaker avatar
has an empty src, which will result in a broken
image displaying. There is also disconnect with
non-react code trying to set an undefined src.
To prevent such until local avatar generation
work is done in the future, just don't show the
avatar.
* fix(conference): set the room instance earlier
Set the room instance on APP.conference before triggering
a redux update of the conference being set,, because
middleware can then fire and call methods on APP.conference
that depend on the room being set.
* get local participant directly from store instead of from global
This reverts commit 7c911eca96.
I'm dumb. We need global mode because otherwise lastIndex is not updated in the
regex object, which we rely upon, so this is intentional.
e729f0948c contained an off-by-one error:
URI_PROTOCOL_PATTERN includes the colon, so after applyting the regex we are
left with something like '//example.com/room' thus we only need to strip the
first 2 characters.
🤦
Looks like custom-scheme links no longer work in all browsers. They do on
Firefox, but the don't in Chrome and other default browsers.
So, switch to intent links on Android:
https://developer.chrome.com/multidevice/android/intents
Example:
```
<a href="intent://meet.jit.si/test123#Intent;scheme=org.jitsi.meet;package=org.jitsi.meet;end">Open Jitsi Meet</a>
```
Dominant speaker events can trigger local participant updates
without a display name. Do not update the name unless there
is an explicit update in the action.
Instead of bundling it in lib-jitsi-meet, which unnecessarily increases
lib-jitsi-meet's bundle size, polyfill it here so it's available in the global
scope, just like the web does.
* feat(Android): implement ConnectionService
Adds basic integration with Android's ConnectionService by implementing
the outgoing call scenario.
* ref(callkit): rename _SET_CALLKIT_SUBSCRIPTIONS
* ref(callkit): move feature to call-integration directory
* feat(ConnectionService): synchronize video state
* ref(AudioMode): use ConnectionService on API >= 26
Not ready yet - few details left mentioned in the FIXMEs
* feat(ConnectionService): add debug logs
Adds logs to trace the calls.
* fix(ConnectionService): leaking ConnectionImpl instances
Turns out there is no callback fired back from the JavaScript side after
the disconnect or abort event is sent from the native. The connection
must be marked as disconnected and removed immediately.
* feat(ConnectionService): handle onCreateOutgoingConnectionFailed
* ref(ConnectionService): merge classes and move to the sdk package
* feat(CallIntegration): show Alert if outgoing call fails
* fix(ConnectionService): alternatively get call UUID from the account
Some Android flavours (or versions ?) do copy over extras to
the onCreateOutgoingConnectionFailed callback. But the call UUID is also
set as the PhoneAccount's label, so eventually it should be available
there.
* ref(ConnectionService): use call UUID as PhoneAccount ID.
The extra is not reliable on some custom Android flavours. It also makes
sense to use unique id for the account instead of the URL given that
it's created on the per call basis.
* fix(ConnectionService): abort the call when hold is requested
Turns out Android P can sometimes request HOLD even though there's no
HOLD capability added to the connection (what!?), so just abort the call
in that case.
* fix(ConnectionService): unregister account on call failure
Unregister the PhoneAccount onCreateOutgoingConnectionFailed. That's
before the ConnectionImpl instance is created which is normally
responsible for doing that.
* fix(AudioModeModule): make package private and run on the audio thread
* address other review comments
* fix(local-recording): allow config override to enable
Config overrides are not set until some time after
APP_WILL_MOUNT has completed and not in the same execution
context as when APP_WILL_MOUNT is called. So instead
choose recording controller initialization at a later time.
The time chosen is after conference join because the
controller needs the conference instance to work.
* remove redundant conditional check
Analytics is erroring when unpinning because the logged
event sends null for the objectId. The objectId should
be the id of the person getting unpinned.
This feature is intended for spot. Spot can have an
HDMI -> usb adapter hooked up to it. In that case,
attempting to screenshare should use that adapter
as a screensharing source. Jitsi-Meet should pass
a configured screenshare source into lib-jitsi-meet
so it can be used as a source.
This is done to kill off the last deprecated lifecycle
usage. There is special logic within index.native to get a
default meeting url by asynchronously fetching it, if
a url is not passed initially. The url is then put onto
state and overridable on subsequent prop updates.
Provide a default and builtin default implementation which finishes the
Activity, same as before.
What this PR removes is the ability to provide a custom default handler because
applications can already take this decision when calling `onBackPressed`. In
addition, make `onBackPressed` return `void` because it's virtually impossible
for it to return `false` (that would mean that there is no
`ReactInstanceManager`, which means there is no app to begin with).
In addition, remove the use of `BackAndroid` since `BackHandler` contains an iOS
shim now.
Instead of handling the side effect of navigating to another
url from within componentWillReceiveProps, try to match the
same logic instead in componentDidUpdate.
Touch feedback manifests in some ugly black border bleeding out of the thumbnail
itself. Since we already provide feedback (be that by adding the blue border in
case of pinning, or showing the menu in case of long press) the perception is
the same, without the graphical glitch.
- Reset some state on the singletons conference
and VideoLayout.
- Add a way for LocalVideo to clean itself up
by sharing logic with the other SmallVideos.
- Add clearing of chat messages so they don't
linger.
- Remove some UI event listeners.
componentWillMount is a deprecated lifecycle method;
componentDidMount should be used to kick off things
like ajax. In the case of the _App hierarchy, a promise
chain is used to perform initialization, and it is
first started in the constructor by initializing
storage. However, by the time storage is initialized,
resolving the first promise, _App has already mounted.
So, move it all to the componentDidMount lifecycle.
The package now requires using a ModalTransition component
to handle animations. The existing DialogContainer component
has been split into native and web implementations to support
this change.
It's possible for the YouTube api to return zero broadcasts
or broadcasts without any streams--streams are what are
associated with stream keys. In this case, instead of showing
an empty selector or no selector, show a message with a link
to where the stream key can be obtained.
Provide a client-side notice if the YouTube live stream key
looks like it might be in the wrong format. Normally the
stream key looks like 4 groups of 4 numbers and letters,
each separated by a dash. The warning does not block submission
in case YouTube changes their stream key format.
Updating react-native-fast-image brings a couple of interesting changes:
- onLoad is not called for cached images (reported and ignored upstream)
- load progress not working if component not displayed (on Android)
In order to fix this, a combination of 2 approaches was used:
- onLoadEnd / onError are used to detect if the image is loaded
- off-screen rendering is used on Android to get progress events
While implementing the above, yours truly noticed the complexity was increasing
way too much, so some extra refactoring was also performed:
- componentWillReceiveProps is dropped
- an auxiliary component (AvatarContent) is used for the actual content of the
Avatar, with the former passing the key prop to the latter
Using the key prop ensures AvatarContent will be recreated if the URI changes,
which is not a bad idea anyway, since the new image needs to be downloaded.
* Replaces smileys and the logic of replacing links/emails.
Now using react-emoji-render and react-linkify.
* Fixes heart emoji.
It is known that current implementation doesn't work with ascii emojis that contain < or >, like >:( >:-( </3 <\3 <3. Making those work may bring some xss issues.
* Adds '_blank' and 'noopener noreferrer' to the replaced links.
* Fixes package-lock links (http vs https).
* Fixes comments.
The upstream package has been unmaintained for 2 years now, and making the litle
changes needed as React Native needs them is getting old. The actual
funcionality is a couple of one-liners plus tons of boliterplate, which gets
reduced by quite a bit if we just embed it. So here it goes.
It doesn't seem like videoTrack needs to be set onto state
if it can be accessed directly from props. Removing the state
automatically removes the deprecated componentWillReceiveProps.
Filmstrip remote thumbnails display under certain conditions, as
defined in filmstrip/functions.web.js. Previously the raw
participant count was used, which included fake participants.
Using the selector getParticipantCount excludes fake participants,
causing YouTube thumbnails to remain hidden in a 1-on-1 call.
- Derive the showOverlay state. When the sidebar should be hidden,
the internal showOverlay state should remain true until the
animation hides it. When the sidebar should show, the showOverlay
state should become true immediately.
- Use PureComponent to prevent additional animation triggers
instead of explicitly checking changes to the "show" prop.