diff --git a/conference.js b/conference.js
index 7d0fe81d8c..60f8a05d3f 100644
--- a/conference.js
+++ b/conference.js
@@ -1867,7 +1867,6 @@ export default {
await this.useVideoStream(desktopVideoStream);
}
-
if (this._desktopAudioStream) {
// If there is a localAudio stream, mix in the desktop audio stream captured by the screen sharing
// api.
@@ -2463,8 +2462,8 @@ export default {
});
APP.UI.addListener(
- UIEvents.TOGGLE_SCREENSHARING, audioOnly => {
- this.toggleScreenSharing(undefined, { audioOnly });
+ UIEvents.TOGGLE_SCREENSHARING, ({ enabled, audioOnly }) => {
+ this.toggleScreenSharing(enabled, { audioOnly });
}
);
},
diff --git a/css/main.scss b/css/main.scss
index b9ab729cf4..dac44f5859 100644
--- a/css/main.scss
+++ b/css/main.scss
@@ -41,6 +41,8 @@ $flagsImagePath: "../images/";
@import 'modals/feedback/feedback';
@import 'modals/invite/info';
@import 'modals/settings/settings';
+@import 'modals/screen-share/share-audio';
+@import 'modals/screen-share/share-screen-warning';
@import 'modals/speaker_stats/speaker_stats';
@import 'modals/video-quality/video-quality';
@import 'modals/virtual-background/virtual-background';
diff --git a/css/modals/screen-share/_share-audio.scss b/css/modals/screen-share/_share-audio.scss
new file mode 100644
index 0000000000..1af3a368c6
--- /dev/null
+++ b/css/modals/screen-share/_share-audio.scss
@@ -0,0 +1,22 @@
+.share-audio-dialog {
+ .share-audio-animation {
+ width: 100%;
+ height: 90%;
+ object-fit: contain;
+ }
+ input[type="checkbox"] + svg + span {
+ color: #9FB0CC;
+ }
+
+ .separator-line {
+ margin: 24px 0 24px -20px;
+ padding: 0 20px;
+ width: 100%;
+ height: 1px;
+ background: #5E6D7A;
+
+ &:last-child {
+ display: none;
+ }
+ }
+}
\ No newline at end of file
diff --git a/css/modals/screen-share/_share-screen-warning.scss b/css/modals/screen-share/_share-screen-warning.scss
new file mode 100644
index 0000000000..a6bea32a80
--- /dev/null
+++ b/css/modals/screen-share/_share-screen-warning.scss
@@ -0,0 +1,23 @@
+.share-screen-warn-dialog {
+ font-size: 14px;
+
+ .separator-line {
+ margin: 24px 0 24px -20px;
+ padding: 0 20px;
+ width: 100%;
+ height: 1px;
+ background: #5E6D7A;
+
+ &:last-child {
+ display: none;
+ }
+ }
+
+ .header {
+ font-weight: 600;
+ }
+
+ .description {
+ margin-top: 16px;
+ }
+}
\ No newline at end of file
diff --git a/images/share-audio.gif b/images/share-audio.gif
new file mode 100644
index 0000000000..756493d39a
Binary files /dev/null and b/images/share-audio.gif differ
diff --git a/lang/main.json b/lang/main.json
index 4db1fc9b49..de77b7378c 100644
--- a/lang/main.json
+++ b/lang/main.json
@@ -215,6 +215,7 @@
"gracefulShutdown": "Our service is currently down for maintenance. Please try again later.",
"grantModeratorDialog": "Are you sure you want to make this participant a moderator?",
"grantModeratorTitle": "Grant moderator",
+ "hideShareAudioHelper": "Don't show this dialog again",
"IamHost": "I am the host",
"incorrectRoomLockPassword": "Incorrect password",
"incorrectPassword": "Incorrect username or password",
@@ -303,6 +304,13 @@
"sessTerminated": "Call terminated",
"sessionRestarted": "Call restarted by the bridge",
"Share": "Share",
+ "shareAudio": "Continue",
+ "shareAudioTitle" : "How to share audio",
+ "shareAudioWarningTitle": "You need to stop screen sharing before sharing audio",
+ "shareAudioWarningH1": "If you want to share just audio:",
+ "shareAudioWarningD1": "you need to stop screen sharing before sharing your audio.",
+ "shareAudioWarningD2": "you need to restart your screen sharing and check the \"share audio\" option.",
+ "shareMediaWarningGenericH2": "If you want to share your screen and audio",
"shareVideoLinkError": "Please provide a correct youtube link.",
"shareVideoTitle": "Share video",
"shareYourScreen": "Share your screen",
@@ -310,6 +318,10 @@
"startLiveStreaming": "Start live stream",
"startRecording": "Start recording",
"startRemoteControlErrorMessage": "An error occurred while trying to start the remote control session!",
+ "shareScreenWarningTitle": "You need to stop audio sharing before sharing your screen",
+ "shareScreenWarningH1": "If you want to share just your screen:",
+ "shareScreenWarningD1": "you need to stop audio sharing before sharing your screen.",
+ "shareScreenWarningD2": "you need to stop audio sharing, start screen sharing and check the \"share audio\" option.",
"stopLiveStreaming": "Stop live stream",
"stopRecording": "Stop recording",
"stopRecordingWarning": "Are you sure you would like to stop the recording?",
@@ -544,7 +556,7 @@
"passwordSetRemotely": "$t(lockRoomPasswordUppercase) set by another participant",
"raisedHand": "{{name}} would like to speak.",
"screenShareNoAudio": " Share audio box was not checked in the window selection screen.",
- "screenShareNoAudioTitle": "Share audio was not checked",
+ "screenShareNoAudioTitle": "Couldn't share system audio!",
"somebody": "Somebody",
"startSilentTitle": "You joined with no audio output!",
"startSilentDescription": "Rejoin the meeting to enable audio",
@@ -899,6 +911,7 @@
"speakerStats": "Speaker stats",
"startScreenSharing": "Start screen sharing",
"startSubtitles": "Start subtitles",
+ "stopAudioSharing": "Stop audio sharing",
"stopScreenSharing": "Stop screen sharing",
"stopSubtitles": "Stop subtitles",
"stopSharedVideo": "Stop video",
diff --git a/modules/API/API.js b/modules/API/API.js
index 19c2ad7f10..e29d3d69fb 100644
--- a/modules/API/API.js
+++ b/modules/API/API.js
@@ -49,6 +49,8 @@ import {
import { toggleLobbyMode } from '../../react/features/lobby/actions';
import { RECORDING_TYPES } from '../../react/features/recording/constants';
import { getActiveSession } from '../../react/features/recording/functions';
+import { isScreenAudioSupported } from '../../react/features/screen-share';
+import { startScreenShareFlow, startAudioScreenShareFlow } from '../../react/features/screen-share/actions';
import { playSharedVideo, stopSharedVideo } from '../../react/features/shared-video/actions.any';
import { toggleTileView, setTileView } from '../../react/features/video-layout';
import { muteAllParticipants } from '../../react/features/video-menu/actions';
@@ -220,6 +222,16 @@ function initCommands() {
sendAnalytics(createApiEvent('raise-hand.toggled'));
APP.store.dispatch(raiseHand(!raisedHand));
},
+ 'toggle-share-audio': () => {
+ sendAnalytics(createApiEvent('audio.screen.sharing.toggled'));
+ if (isScreenAudioSupported()) {
+ APP.store.dispatch(startAudioScreenShareFlow());
+
+ return;
+ }
+
+ logger.error('Audio screen sharing is not supported by the current platform!');
+ },
/**
* Callback to invoke when the "toggle-share-screen" command is received.
@@ -596,9 +608,7 @@ function shouldBeEnabled() {
*/
function toggleScreenSharing(enable) {
if (JitsiMeetJS.isDesktopSharingEnabled()) {
- APP.conference.toggleScreenSharing(enable).catch(() => {
- logger.warn('Failed to toggle screen-sharing');
- });
+ APP.store.dispatch(startScreenShareFlow(enable));
}
}
diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js
index cbcd52bfe4..1cd3884ae5 100644
--- a/modules/API/external/external_api.js
+++ b/modules/API/external/external_api.js
@@ -60,6 +60,7 @@ const commands = {
toggleChat: 'toggle-chat',
toggleFilmStrip: 'toggle-film-strip',
toggleRaiseHand: 'toggle-raise-hand',
+ toggleShareAudio: 'toggle-share-audio',
toggleShareScreen: 'toggle-share-screen',
toggleTileView: 'toggle-tile-view',
toggleVirtualBackgroundDialog: 'toggle-virtual-background',
diff --git a/react/features/base/icons/svg/index.js b/react/features/base/icons/svg/index.js
index 22cb816cdc..fc270d53a6 100644
--- a/react/features/base/icons/svg/index.js
+++ b/react/features/base/icons/svg/index.js
@@ -111,6 +111,7 @@ export { default as IconShareDesktop } from './share-desktop.svg';
export { default as IconShareDoc } from './share-doc.svg';
export { default as IconShareVideo } from './shared-video.svg';
export { default as IconSmile } from './smile.svg';
+export { default as IconStopAudioShare } from './stop-audio-share.svg';
export { default as IconSwitchCamera } from './switch-camera.svg';
export { default as IconTileView } from './tiles-many.svg';
export { default as IconToggleRecording } from './camera-take-picture.svg';
diff --git a/react/features/base/icons/svg/stop-audio-share.svg b/react/features/base/icons/svg/stop-audio-share.svg
new file mode 100644
index 0000000000..a66b2d2b4a
--- /dev/null
+++ b/react/features/base/icons/svg/stop-audio-share.svg
@@ -0,0 +1,3 @@
+
diff --git a/react/features/base/settings/functions.any.js b/react/features/base/settings/functions.any.js
index 9332da7941..9eda3ff640 100644
--- a/react/features/base/settings/functions.any.js
+++ b/react/features/base/settings/functions.any.js
@@ -248,3 +248,13 @@ function _getUserSelectedDeviceId(options) {
? foundMatchBasedOnLabel.deviceId : userSelectedDeviceId;
}
+/**
+ * Should we hide the helper dialog when a user tries to do audio only screen sharing.
+ *
+ * @param {Object} state - The state of the application.
+ * @returns {boolean}
+ */
+export function shouldHideShareAudioHelper(state: Object): boolean {
+
+ return state['features/base/settings'].hideShareAudioHelper;
+}
diff --git a/react/features/base/settings/reducer.js b/react/features/base/settings/reducer.js
index fb809b7c92..4536c47314 100644
--- a/react/features/base/settings/reducer.js
+++ b/react/features/base/settings/reducer.js
@@ -26,6 +26,7 @@ const DEFAULT_STATE = {
localFlipX: true,
micDeviceId: undefined,
serverURL: undefined,
+ hideShareAudioHelper: false,
startAudioOnly: false,
startWithAudioMuted: false,
startWithVideoMuted: false,
diff --git a/react/features/base/tracks/middleware.js b/react/features/base/tracks/middleware.js
index 27882f699f..a412925446 100644
--- a/react/features/base/tracks/middleware.js
+++ b/react/features/base/tracks/middleware.js
@@ -145,7 +145,10 @@ MiddlewareRegistry.register(store => next => action => {
return;
}
- APP.UI.emitEvent(UIEvents.TOGGLE_SCREENSHARING, action.audioOnly);
+ const { enabled, audioOnly } = action;
+
+ APP.UI.emitEvent(UIEvents.TOGGLE_SCREENSHARING, { enabled,
+ audioOnly });
}
break;
diff --git a/react/features/screen-share/actions.js b/react/features/screen-share/actions.js
index 8f5b9b3b5c..2ef9c056ee 100644
--- a/react/features/screen-share/actions.js
+++ b/react/features/screen-share/actions.js
@@ -1,6 +1,14 @@
// @flow
+import { openDialog } from '../base/dialog/actions';
+import { browser } from '../base/lib-jitsi-meet';
+import { shouldHideShareAudioHelper } from '../base/settings';
+import { toggleScreensharing } from '../base/tracks';
+
import { SET_SCREEN_AUDIO_SHARE_STATE, SET_SCREENSHARE_CAPTURE_FRAME_RATE } from './actionTypes';
+import { ShareAudioDialog } from './components';
+import ShareMediaWarningDialog from './components/ShareScreenWarningDialog';
+import { isAudioOnlySharing, isScreenVideoShared } from './functions';
/**
* Updates the current known status of the shared video.
@@ -33,3 +41,61 @@ export function setScreenshareFramerate(captureFrameRate: number) {
captureFrameRate
};
}
+
+/**
+ * Start the audio only screen sharing flow. Function will switch between off and on states depending on the context.
+ *
+ * @param {Object} state - The state of the application.
+ * @returns {void}
+ */
+export function startAudioScreenShareFlow() {
+ return (dispatch: Object => Object, getState: () => any) => {
+ const state = getState();
+ const audioOnlySharing = isAudioOnlySharing(state);
+
+ // If we're already in a normal screen sharing session, warn the user.
+ if (isScreenVideoShared(state)) {
+ dispatch(openDialog(ShareMediaWarningDialog, { _isAudioScreenShareWarning: true }));
+
+ return;
+ }
+
+ // If users opted out of the helper dialog toggle directly.
+ // If we're in an electron environment the helper dialog is not needed as there's only one option
+ // available for audio screen sharing, namely full window audio.
+ // If we're already sharing audio, toggle off.
+ if (shouldHideShareAudioHelper(state) || browser.isElectron() || audioOnlySharing) {
+ // We don't want to explicity set the screens share state, by passing undefined we let the
+ // underlying logic decide if it's on or off.
+ dispatch(toggleScreensharing(undefined, true));
+
+ return;
+ }
+
+ dispatch(openDialog(ShareAudioDialog));
+ };
+}
+
+/**
+ * Start normal screen sharing flow.Function will switch between off and on states depending on the context, and if
+ * not explicity told otherwise.
+ *
+ * @param {boolean} enabled - Explicitly set the screen sharing state. This has been kept for backward compatibility
+ * with the external API exposed by the iframe, even though it might not be used.
+ * @returns {void}
+ */
+export function startScreenShareFlow(enabled: boolean) {
+ return (dispatch: Object => Object, getState: () => any) => {
+ const state = getState();
+ const audioOnlySharing = isAudioOnlySharing(state);
+
+ // If we're in an audio screen sharing session, warn the user.
+ if (audioOnlySharing) {
+ dispatch(openDialog(ShareMediaWarningDialog, { _isAudioScreenShareWarning: false }));
+
+ return;
+ }
+
+ dispatch(toggleScreensharing(enabled));
+ };
+}
diff --git a/react/features/screen-share/components/ShareAudioButton.js b/react/features/screen-share/components/ShareAudioButton.js
new file mode 100644
index 0000000000..d8ab1dd717
--- /dev/null
+++ b/react/features/screen-share/components/ShareAudioButton.js
@@ -0,0 +1,80 @@
+// @flow
+
+import type { Dispatch } from 'redux';
+
+import { translate } from '../../base/i18n';
+import {
+ IconShareAudio,
+ IconStopAudioShare
+} from '../../base/icons';
+import { connect } from '../../base/redux';
+import {
+ AbstractButton,
+ type AbstractButtonProps
+} from '../../base/toolbox/components';
+import { setOverflowMenuVisible } from '../../toolbox/actions';
+import { startAudioScreenShareFlow } from '../actions';
+import { isAudioOnlySharing } from '../functions';
+
+type Props = AbstractButtonProps & {
+
+ /**
+ * The redux {@code dispatch} function.
+ */
+ dispatch: Dispatch,
+
+ /**
+ * Whether or not the local participant is audio only screen sharing.
+ */
+ _isAudioOnlySharing: boolean
+}
+
+/**
+ * Component that renders a toolbar button for toggling audio only screen share.
+ */
+class ShareAudioButton extends AbstractButton {
+ accessibilityLabel = 'toolbar.accessibilityLabel.shareaudio';
+ icon = IconShareAudio;
+ label = 'toolbar.shareaudio';
+ tooltip = 'toolbar.shareaudio';
+ toggledIcon = IconStopAudioShare;
+ toggledLabel = 'toolbar.stopAudioSharing';
+
+ /**
+ * Handles clicking / pressing the button, and opens a new dialog.
+ *
+ * @private
+ * @returns {void}
+ */
+ _handleClick() {
+ this.props.dispatch(startAudioScreenShareFlow());
+ this.props.dispatch(setOverflowMenuVisible(false));
+ }
+
+ /**
+ * Indicates whether this button is in toggled state or not.
+ *
+ * @override
+ * @protected
+ * @returns {boolean}
+ */
+ _isToggled() {
+ return this.props._isAudioOnlySharing;
+ }
+}
+
+/**
+ * Maps part of the Redux state to the props of this component.
+ *
+ * @param {Object} state - The Redux state.
+ * @private
+ * @returns {Props}
+ */
+function _mapStateToProps(state: Object): $Shape {
+
+ return {
+ _isAudioOnlySharing: isAudioOnlySharing(state)
+ };
+}
+
+export default translate(connect(_mapStateToProps)(ShareAudioButton));
diff --git a/react/features/screen-share/components/ShareAudioDialog.js b/react/features/screen-share/components/ShareAudioDialog.js
new file mode 100644
index 0000000000..6fb1fdb37d
--- /dev/null
+++ b/react/features/screen-share/components/ShareAudioDialog.js
@@ -0,0 +1,128 @@
+// @flow
+
+import { Checkbox } from '@atlaskit/checkbox';
+import React, { Component } from 'react';
+import type { Dispatch } from 'redux';
+
+import { Dialog } from '../../base/dialog';
+import { translate } from '../../base/i18n';
+import { connect } from '../../base/redux';
+import {
+ updateSettings,
+ shouldHideShareAudioHelper
+} from '../../base/settings';
+import { toggleScreensharing } from '../../base/tracks';
+
+/**
+ * The type of the React {@code Component} props of {@link ShareAudioDialog}.
+ */
+export type Props = {
+
+ /**
+ * The redux {@code dispatch} function.
+ */
+ dispatch: Dispatch,
+
+ /**
+ * Boolean stored in local storage that determines whether or not the dialog will be displayed again.
+ */
+ _shouldHideShareAudioHelper: boolean,
+
+ /**
+ * Invoked to obtain translated strings.
+ */
+ t: Function
+};
+
+/**
+ * Component that displays the audio screen share helper dialog.
+ */
+class ShareAudioDialog extends Component {
+
+ /**
+ * Instantiates a new component.
+ *
+ * @inheritdoc
+ */
+ constructor(props) {
+ super(props);
+
+ this._onContinue = this._onContinue.bind(this);
+ this._onSelectHideShareAudioHelper = this._onSelectHideShareAudioHelper.bind(this);
+ }
+
+ _onContinue: () => boolean;
+
+ /**
+ * Continue the normal screen sharing flow when the user clicks continue.
+ *
+ * @returns {boolean}
+ */
+ _onContinue() {
+ // Pass undefined as the first parameter so the underlying logic decides weather or not to stop screen sharing.
+ this.props.dispatch(toggleScreensharing(undefined, true));
+
+ return true;
+ }
+
+ _onSelectHideShareAudioHelper: (Object) => void;
+
+ /**
+ * Callback invoked when the hide audio helper checkbox has been selected. This setting will be persisted in
+ * the local storage, thus the dialog won't be displayed again.
+ *
+ * @param {Object} e - The key event to handle.
+ * @returns {void}
+ */
+ _onSelectHideShareAudioHelper({ target: { checked } }) {
+ this.props.dispatch(updateSettings({ hideShareAudioHelper: checked }));
+ }
+
+ /**
+ * Implements {@Component#render}.
+ *
+ * @inheritdoc
+ */
+ render() {
+
+ const { t } = this.props;
+
+ return (
+
+ );
+ }
+}
+
+/**
+ * Maps part of the Redux state to the props of this component.
+ *
+ * @param {Object} state - The Redux state.
+ * @private
+ * @returns {Props}
+ */
+function _mapStateToProps(state: Object): $Shape {
+
+ return {
+ _shouldHideShareAudioHelper: shouldHideShareAudioHelper(state)
+ };
+}
+
+
+export default translate(connect(_mapStateToProps)(ShareAudioDialog));
diff --git a/react/features/screen-share/components/ShareScreenWarningDialog.js b/react/features/screen-share/components/ShareScreenWarningDialog.js
new file mode 100644
index 0000000000..12ff5e7002
--- /dev/null
+++ b/react/features/screen-share/components/ShareScreenWarningDialog.js
@@ -0,0 +1,105 @@
+// @flow
+
+import React, { Component } from 'react';
+import type { Dispatch } from 'redux';
+
+import { Dialog } from '../../base/dialog';
+import { translate } from '../../base/i18n';
+import { connect } from '../../base/redux';
+import { toggleScreensharing } from '../../base/tracks';
+
+export type Props = {
+
+ /**
+ * The redux {@code dispatch} function.
+ */
+ dispatch: Dispatch,
+
+ /**
+ * Whether or not the dialog was opened for the audio screen sharing flow or the normal one.
+ */
+ _isAudioScreenShareWarning: Boolean,
+
+ /**
+ * Invoked to obtain translated strings.
+ */
+ t: Function
+}
+
+/**
+ * Component that displays the share audio helper dialog.
+ */
+class ShareScreenWarningDialog extends Component {
+
+ /**
+ * Instantiates a new component.
+ *
+ * @inheritdoc
+ */
+ constructor(props) {
+ super(props);
+
+ this._onStopSharing = this._onStopSharing.bind(this);
+ }
+
+ _onStopSharing: () => boolean;
+
+ /**
+ * Stop current screen sharing session.
+ *
+ * @returns {boolean}
+ */
+ _onStopSharing() {
+ // Depending on the context from which this dialog is opened we'll either be toggling off an audio only
+ // share session or a normal screen sharing one, this is indicated by the _isAudioScreenShareWarning prop.
+ this.props.dispatch(toggleScreensharing(undefined,
+ !this.props._isAudioScreenShareWarning));
+
+ return true;
+ }
+
+ /**
+ * Implements {@Component#render}.
+ *ยง
+ * @inheritdoc
+ */
+ render() {
+ const { t } = this.props;
+
+ let description1, description2, header1, header2, stopSharing, title;
+
+ if (this.props._isAudioScreenShareWarning) {
+ header1 = 'dialog.shareAudioWarningH1';
+ header2 = 'dialog.shareMediaWarningGenericH2';
+ description1 = 'dialog.shareAudioWarningD1';
+ description2 = 'dialog.shareAudioWarningD2';
+ title = 'dialog.shareAudioWarningTitle';
+ stopSharing = 'toolbar.stopScreenSharing';
+ } else {
+ header1 = 'dialog.shareScreenWarningTitle';
+ header2 = 'dialog.shareMediaWarningGenericH2';
+ description1 = 'dialog.shareScreenWarningD1';
+ description2 = 'dialog.shareScreenWarningD2';
+ title = 'dialog.shareScreenWarningTitle';
+ stopSharing = 'toolbar.stopAudioSharing';
+ }
+
+ return ();
+
+ }
+}
+
+export default translate(connect()(ShareScreenWarningDialog));
diff --git a/react/features/screen-share/components/index.js b/react/features/screen-share/components/index.js
new file mode 100644
index 0000000000..bc993d82d7
--- /dev/null
+++ b/react/features/screen-share/components/index.js
@@ -0,0 +1,2 @@
+export { default as ShareAudioButton } from './ShareAudioButton';
+export { default as ShareAudioDialog } from './ShareAudioDialog';
diff --git a/react/features/screen-share/functions.js b/react/features/screen-share/functions.js
index 401a4aaf0c..9a9e536927 100644
--- a/react/features/screen-share/functions.js
+++ b/react/features/screen-share/functions.js
@@ -1,8 +1,20 @@
// @flow
import { isWindows } from '../base/environment';
+import { isMobileBrowser } from '../base/environment/utils';
import { browser } from '../base/lib-jitsi-meet';
+import { VIDEO_TYPE } from '../base/media';
+import { getLocalVideoTrack } from '../base/tracks';
+/**
+ * Is the current screen sharing session audio only.
+ *
+ * @param {Object} state - The state of the application.
+ * @returns {boolean}
+ */
+export function isAudioOnlySharing(state: Object) {
+ return isScreenAudioShared(state) && !isScreenVideoShared(state);
+}
/**
* State of audio sharing.
@@ -21,5 +33,28 @@ export function isScreenAudioShared(state: Object) {
* @returns {boolean}
*/
export function isScreenAudioSupported() {
- return browser.isChrome() || (browser.isElectron() && isWindows());
+ return (!isMobileBrowser() && browser.isChrome()) || (browser.isElectron() && isWindows());
+}
+
+/**
+ * Is any screen media currently being shared, audio or video.
+ *
+ * @param {Object} state - The state of the application.
+ * @returns {boolean}
+ */
+export function isScreenMediaShared(state: Object) {
+ return isScreenAudioShared(state) || isScreenVideoShared(state);
+}
+
+/**
+ * Is screen sharing currently active.
+ *
+ * @param {Object} state - The state of the application.
+ * @returns {boolean}
+ */
+export function isScreenVideoShared(state: Object) {
+ const localVideo = getLocalVideoTrack(state['features/base/tracks']);
+
+ // $FlowFixMe - No support for optional chain method calls in flow atm.
+ return localVideo?.jitsiTrack?.getVideoType() === VIDEO_TYPE.DESKTOP;
}
diff --git a/react/features/screen-share/index.js b/react/features/screen-share/index.js
index 7461a8bcfd..e41fc768ee 100644
--- a/react/features/screen-share/index.js
+++ b/react/features/screen-share/index.js
@@ -1,4 +1,6 @@
+
export * from './actions';
export * from './actionTypes';
+export * from './components';
export * from './functions';
diff --git a/react/features/toolbox/components/web/Toolbox.js b/react/features/toolbox/components/web/Toolbox.js
index a952374f33..bb49328d10 100644
--- a/react/features/toolbox/components/web/Toolbox.js
+++ b/react/features/toolbox/components/web/Toolbox.js
@@ -25,7 +25,6 @@ import {
IconPresentation,
IconRaisedHand,
IconRec,
- IconShareAudio,
IconShareDesktop
} from '../../../base/icons';
import JitsiMeetJS from '../../../base/lib-jitsi-meet';
@@ -36,7 +35,7 @@ import {
} from '../../../base/participants';
import { connect } from '../../../base/redux';
import { OverflowMenuItem } from '../../../base/toolbox/components';
-import { getLocalVideoTrack, toggleScreensharing } from '../../../base/tracks';
+import { getLocalVideoTrack } from '../../../base/tracks';
import { isVpaasMeeting } from '../../../billing-counter/functions';
import { ChatCounter, toggleChat } from '../../../chat';
import { EmbedMeetingDialog } from '../../../embed-meeting';
@@ -53,7 +52,12 @@ import {
LiveStreamButton,
RecordButton
} from '../../../recording';
-import { isScreenAudioShared, isScreenAudioSupported } from '../../../screen-share/';
+import {
+ isScreenAudioSupported,
+ isScreenVideoShared,
+ ShareAudioButton,
+ startScreenShareFlow
+} from '../../../screen-share/';
import SecurityDialogButton from '../../../security/components/security-dialog/SecurityDialogButton';
import {
SETTINGS_TABS,
@@ -287,7 +291,6 @@ class Toolbox extends Component {
this._onToolbarToggleProfile = this._onToolbarToggleProfile.bind(this);
this._onToolbarToggleRaiseHand = this._onToolbarToggleRaiseHand.bind(this);
this._onToolbarToggleScreenshare = this._onToolbarToggleScreenshare.bind(this);
- this._onToolbarToggleShareAudio = this._onToolbarToggleShareAudio.bind(this);
this._onToolbarOpenLocalRecordingInfoDialog = this._onToolbarOpenLocalRecordingInfoDialog.bind(this);
this._onShortcutToggleTileView = this._onShortcutToggleTileView.bind(this);
this._onEscKey = this._onEscKey.bind(this);
@@ -535,9 +538,9 @@ class Toolbox extends Component {
* @param {boolean} audioOnly - Only share system audio.
* @returns {void}
*/
- _doToggleScreenshare(enabled, audioOnly = false) {
+ _doToggleScreenshare() {
if (this.props._desktopSharingEnabled) {
- this.props.dispatch(toggleScreensharing(enabled, audioOnly));
+ this.props.dispatch(startScreenShareFlow());
}
}
@@ -725,15 +728,13 @@ class Toolbox extends Component {
* @returns {void}
*/
_onShortcutToggleScreenshare() {
- const enable = !this.props._screensharing;
-
sendAnalytics(createToolbarEvent(
'screen.sharing',
{
- enable
+ enable: !this.props._screensharing
}));
- this._doToggleScreenshare(enable);
+ this._doToggleScreenshare();
}
_onTabIn: () => void;
@@ -940,29 +941,13 @@ class Toolbox extends Component {
return;
}
- const enable = !this.props._screensharing;
-
sendAnalytics(createShortcutEvent(
'toggle.screen.sharing',
ACTION_SHORTCUT_TRIGGERED,
- { enable }));
+ { enable: !this.props._screensharing }));
this._closeOverflowMenuIfOpen();
- this._doToggleScreenshare(enable);
- }
-
- _onToolbarToggleShareAudio: () => void;
-
- /**
- * Handles toggle share audio action.
- *
- * @returns {void}
- */
- _onToolbarToggleShareAudio() {
- const enable = !this.props._screensharing;
-
- this._closeOverflowMenuIfOpen();
- this._doToggleScreenshare(enable, true);
+ this._doToggleScreenshare();
}
_onToolbarOpenLocalRecordingInfoDialog: () => void;
@@ -1095,12 +1080,9 @@ class Toolbox extends Component {
this.props._shouldShowButton('shareaudio')
&& _desktopSharingEnabled
&& isScreenAudioSupported()
- && ,
+ showLabel = { true } />,
this.props._shouldShowButton('etherpad')
&& isToolbarButtonEnabled(buttonName)(state),
_visible: isToolboxVisible(state),
_visibleButtons: getToolbarButtons(state)