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 ( +
+

{ t(header1) }

+

{ t(description1) }

+
+

{ t(header2) }

+

{ t(description2) }

+
+
); + + } +} + +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)