diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 14f0f8d5b46b8..737f82ffea1b1 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -5704,6 +5704,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_group_call_screen_share_stop" = "Stop Sharing"; "lng_group_call_screen_title" = "Screen {index}"; "lng_group_call_screen_share_audio" = "Share System Audio"; +"lng_group_call_sharing_screen_options" = "Sharing Options"; +"lng_group_call_choose_source" = "Choose Source"; "lng_group_call_unmute" = "Unmute"; "lng_group_call_unmute_sub" = "Hold space bar to temporarily unmute."; "lng_group_call_you_are_live" = "You are Live"; diff --git a/Telegram/SourceFiles/calls/calls_call.cpp b/Telegram/SourceFiles/calls/calls_call.cpp index 1abcf70328b28..91b46b066554f 100644 --- a/Telegram/SourceFiles/calls/calls_call.cpp +++ b/Telegram/SourceFiles/calls/calls_call.cpp @@ -1433,7 +1433,9 @@ void Call::toggleCameraSharing(bool enabled) { }), true); } -void Call::toggleScreenSharing(std::optional uniqueId) { +void Call::toggleScreenSharing( + std::optional uniqueId, + bool withAudio) { if (!uniqueId) { if (isSharingScreen()) { if (_videoCapture) { @@ -1443,13 +1445,20 @@ void Call::toggleScreenSharing(std::optional uniqueId) { } _videoCaptureDeviceId = QString(); _videoCaptureIsScreencast = false; + _screenWithAudio = false; + if (_systemAudioCapture) { + _systemAudioCapture->stop(); + _systemAudioCapture = nullptr; + } return; - } else if (screenSharingDeviceId() == *uniqueId) { + } else if (screenSharingDeviceId() == *uniqueId + && _screenWithAudio == withAudio) { return; } toggleCameraSharing(false); _videoCaptureIsScreencast = true; _videoCaptureDeviceId = *uniqueId; + _screenWithAudio = withAudio; if (_videoCapture) { _videoCapture->switchToDevice(uniqueId->toStdString(), true); if (_instance) { @@ -1457,6 +1466,29 @@ void Call::toggleScreenSharing(std::optional uniqueId) { } } _videoOutgoing->setState(Webrtc::VideoState::Active); + + if (_systemAudioCapture) { + _systemAudioCapture->stop(); + _systemAudioCapture = nullptr; + } + if (withAudio && Webrtc::SystemAudioCaptureSupported()) { + _systemAudioCapture = Webrtc::CreateSystemAudioCapture( + [weak = base::make_weak(this)](std::vector &&samples) { + crl::on_main( + weak, + [weak, samples = std::move(samples)]() mutable { + if (const auto strong = weak.get(); strong + && strong->_instance + && strong->_screenWithAudio) { + strong->_instance->addExternalAudioSamples( + std::move(samples)); + } + }); + }); + if (_systemAudioCapture) { + _systemAudioCapture->start(); + } + } } auto Call::peekVideoCapture() const @@ -1617,6 +1649,10 @@ void Call::handleControllerError(const QString &error) { void Call::destroyController() { _instanceLifetime.destroy(); Core::App().mediaDevices().setCaptureMuteTracker(this, false); + if (_systemAudioCapture) { + _systemAudioCapture->stop(); + _systemAudioCapture = nullptr; + } if (_instance) { _instance->stop([](tgcalls::FinalState) { diff --git a/Telegram/SourceFiles/calls/calls_call.h b/Telegram/SourceFiles/calls/calls_call.h index 41ee5dd9ad0ed..d40d0794c40e6 100644 --- a/Telegram/SourceFiles/calls/calls_call.h +++ b/Telegram/SourceFiles/calls/calls_call.h @@ -13,6 +13,7 @@ For license and copyright information please follow this link: #include "mtproto/sender.h" #include "mtproto/mtproto_auth_key.h" #include "webrtc/webrtc_device_resolver.h" +#include "webrtc/webrtc_system_audio_capture.h" namespace Data { class GroupCall; @@ -252,7 +253,12 @@ class Call final [[nodiscard]] QString cameraSharingDeviceId() const; [[nodiscard]] QString screenSharingDeviceId() const; void toggleCameraSharing(bool enabled); - void toggleScreenSharing(std::optional uniqueId); + void toggleScreenSharing( + std::optional uniqueId, + bool withAudio = false); + [[nodiscard]] bool screenSharingWithAudio() const { + return _screenWithAudio; + } [[nodiscard]] auto peekVideoCapture() const -> std::shared_ptr; @@ -366,6 +372,8 @@ class Call final std::shared_ptr _videoCapture; QString _videoCaptureDeviceId; bool _videoCaptureIsScreencast = false; + bool _screenWithAudio = false; + std::unique_ptr _systemAudioCapture; const std::unique_ptr _videoIncoming; const std::unique_ptr _videoOutgoing; diff --git a/Telegram/SourceFiles/calls/calls_panel.cpp b/Telegram/SourceFiles/calls/calls_panel.cpp index 8f57effdfbf10..3031c24b15eaf 100644 --- a/Telegram/SourceFiles/calls/calls_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_panel.cpp @@ -61,6 +61,7 @@ For license and copyright information please follow this link: #include "media/streaming/media_streaming_utility.h" #include "window/main_window.h" #include "window/window_controller.h" +#include "webrtc/webrtc_create_adm.h" #include "webrtc/webrtc_environment.h" #include "webrtc/webrtc_video_track.h" #include "styles/style_calls.h" @@ -395,6 +396,13 @@ void Panel::initControls() { } else if (const auto source = env->uniqueDesktopCaptureSource()) { if (!chooseSourceActiveDeviceId().isEmpty()) { chooseSourceStop(); + } else if (chooseSourceWithAudioSupported()) { + const auto sourceId = *source; + Group::ShowUniqueCaptureOptions( + uiShow(), + crl::guard(this, [=](bool audio) { + chooseSourceAccepted(sourceId, audio); + })); } else { chooseSourceAccepted(*source, false); } @@ -564,15 +572,11 @@ QString Panel::chooseSourceActiveDeviceId() { } bool Panel::chooseSourceActiveWithAudio() { - return false;// _call->screenSharingWithAudio(); + return _call->screenSharingWithAudio(); } bool Panel::chooseSourceWithAudioSupported() { -//#ifdef Q_OS_WIN -// return true; -//#else // Q_OS_WIN - return false; -//#endif // Q_OS_WIN + return Webrtc::LoopbackAudioCaptureSupported(); } rpl::lifetime &Panel::chooseSourceInstanceLifetime() { @@ -589,7 +593,7 @@ rpl::producer Panel::startOutgoingRequests() const { void Panel::chooseSourceAccepted( const QString &deviceId, bool withAudio) { - _call->toggleScreenSharing(deviceId/*, withAudio*/); + _call->toggleScreenSharing(deviceId, withAudio); } void Panel::chooseSourceStop() { diff --git a/Telegram/SourceFiles/calls/group/calls_group_common.cpp b/Telegram/SourceFiles/calls/group/calls_group_common.cpp index 030ba2bdf587a..90c1c18b9f245 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_common.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_common.cpp @@ -22,6 +22,7 @@ For license and copyright information please follow this link: #include "tde2e/tde2e_integration.h" #include "ui/boxes/boost_box.h" #include "ui/widgets/buttons.h" +#include "ui/widgets/checkbox.h" #include "ui/widgets/labels.h" #include "ui/widgets/popup_menu.h" #include "ui/layers/generic_box.h" @@ -77,6 +78,28 @@ object_ptr ScreenSharingPrivacyRequestBox() { #endif // Q_OS_MAC } +void ShowUniqueCaptureOptions( + std::shared_ptr show, + Fn done) { + show->showBox(Box([=](not_null box) { + box->setTitle(tr::lng_group_call_sharing_screen_options()); + const auto withAudio = box->addRow( + object_ptr( + box, + tr::lng_group_call_screen_share_audio(tr::now), + false, + st::groupCallCheckbox)); + box->addButton( + tr::lng_group_call_choose_source(), + [=] { + const auto audio = withAudio->checked(); + box->closeBox(); + done(audio); + }); + box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); + })); +} + object_ptr MakeRoundActiveLogo( not_null parent, const style::icon &icon, diff --git a/Telegram/SourceFiles/calls/group/calls_group_common.h b/Telegram/SourceFiles/calls/group/calls_group_common.h index c0b255c49899a..a75872c4bd50b 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_common.h +++ b/Telegram/SourceFiles/calls/group/calls_group_common.h @@ -162,6 +162,10 @@ using StickedTooltips = base::flags; [[nodiscard]] object_ptr ScreenSharingPrivacyRequestBox(); +void ShowUniqueCaptureOptions( + std::shared_ptr show, + Fn done); + [[nodiscard]] object_ptr MakeRoundActiveLogo( not_null parent, const style::icon &icon, diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp index 02329beaeb0d6..2be0bea399ac5 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp @@ -65,6 +65,7 @@ For license and copyright information please follow this link: #include "webrtc/webrtc_environment.h" #include "webrtc/webrtc_video_track.h" #include "webrtc/webrtc_audio_input_tester.h" +#include "webrtc/webrtc_create_adm.h" #include "styles/style_calls.h" #include "styles/style_layers.h" @@ -356,11 +357,7 @@ bool Panel::chooseSourceActiveWithAudio() { } bool Panel::chooseSourceWithAudioSupported() { -#ifdef Q_OS_WIN - return true; -#else // Q_OS_WIN - return false; -#endif // Q_OS_WIN + return Webrtc::LoopbackAudioCaptureSupported(); } rpl::lifetime &Panel::chooseSourceInstanceLifetime() { @@ -1527,6 +1524,13 @@ void Panel::chooseShareScreenSource() { } else if (const auto source = env->uniqueDesktopCaptureSource()) { if (_call->isSharingScreen()) { _call->toggleScreenSharing(std::nullopt); + } else if (chooseSourceWithAudioSupported()) { + const auto sourceId = *source; + ShowUniqueCaptureOptions( + uiShow(), + crl::guard(this, [=](bool audio) { + chooseSourceAccepted(sourceId, audio); + })); } else { chooseSourceAccepted(*source, false); }