Allow sharing screen with sound on Windows.

This commit is contained in:
John Preston 2021-07-13 16:27:44 +03:00
parent 402729dc99
commit db81638656
13 changed files with 129 additions and 27 deletions

View File

@ -2021,6 +2021,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_call_screen_share_start" = "Share Screen"; "lng_group_call_screen_share_start" = "Share Screen";
"lng_group_call_screen_share_stop" = "Stop Sharing"; "lng_group_call_screen_share_stop" = "Stop Sharing";
"lng_group_call_screen_title" = "Screen {index}"; "lng_group_call_screen_title" = "Screen {index}";
"lng_group_call_screen_share_audio" = "Share Audio";
"lng_group_call_unmute_small" = "Unmute"; "lng_group_call_unmute_small" = "Unmute";
"lng_group_call_more" = "More"; "lng_group_call_more" = "More";
"lng_group_call_unmute" = "Unmute"; "lng_group_call_unmute" = "Unmute";

View File

@ -1184,6 +1184,16 @@ desktopCaptureSubmit: RoundButton(desktopCaptureCancel) {
color: shadowFg; color: shadowFg;
} }
} }
desktopCaptureWithAudio: Checkbox(defaultCheckbox) {
textFg: groupCallMembersFg;
textFgActive: groupCallMembersFg;
rippleBg: groupCallMembersBgRipple;
rippleBgActive: groupCallMembersBgRipple;
style: semiboldTextStyle;
}
desktopCaptureWithAudioCheck: Check(defaultCheck) {
untoggledFg: groupCallActiveFg;
}
groupCallNarrowSkip: 9px; groupCallNarrowSkip: 9px;
groupCallNarrowMembersWidth: 204px; groupCallNarrowMembersWidth: 204px;

View File

@ -613,6 +613,10 @@ QString GroupCall::screenSharingDeviceId() const {
return isSharingScreen() ? _screenDeviceId : QString(); return isSharingScreen() ? _screenDeviceId : QString();
} }
bool GroupCall::screenSharingWithAudio() const {
return isSharingScreen() && _screenWithAudio;
}
bool GroupCall::mutedByAdmin() const { bool GroupCall::mutedByAdmin() const {
const auto mute = muted(); const auto mute = muted();
return mute == MuteState::ForceMuted || mute == MuteState::RaisedHand; return mute == MuteState::ForceMuted || mute == MuteState::RaisedHand;
@ -635,7 +639,9 @@ void GroupCall::toggleVideo(bool active) {
: Webrtc::VideoState::Inactive; : Webrtc::VideoState::Inactive;
} }
void GroupCall::toggleScreenSharing(std::optional<QString> uniqueId) { void GroupCall::toggleScreenSharing(
std::optional<QString> uniqueId,
bool withAudio) {
if (!_instance || !_id) { if (!_instance || !_id) {
return; return;
} else if (!uniqueId) { } else if (!uniqueId) {
@ -645,10 +651,14 @@ void GroupCall::toggleScreenSharing(std::optional<QString> uniqueId) {
const auto changed = (_screenDeviceId != *uniqueId); const auto changed = (_screenDeviceId != *uniqueId);
const auto wasSharing = isSharingScreen(); const auto wasSharing = isSharingScreen();
_screenDeviceId = *uniqueId; _screenDeviceId = *uniqueId;
_screenWithAudio = withAudio;
_screenState = Webrtc::VideoState::Active; _screenState = Webrtc::VideoState::Active;
if (changed && wasSharing && isSharingScreen()) { if (changed && wasSharing && isSharingScreen()) {
_screenCapture->switchToDevice(uniqueId->toStdString()); _screenCapture->switchToDevice(uniqueId->toStdString());
} }
if (_screenInstance) {
_screenInstance->setIsMuted(!withAudio);
}
} }
bool GroupCall::hasVideoWithFrames() const { bool GroupCall::hasVideoWithFrames() const {
@ -2281,9 +2291,7 @@ bool GroupCall::tryCreateScreencast() {
_screenInstance = std::make_unique<tgcalls::GroupInstanceCustomImpl>( _screenInstance = std::make_unique<tgcalls::GroupInstanceCustomImpl>(
std::move(descriptor)); std::move(descriptor));
#ifdef Q_OS_WIN _screenInstance->setIsMuted(!_screenWithAudio);
_screenInstance->setIsMuted(false);
#endif // Q_OS_WIN
return true; return true;
} }

View File

@ -380,8 +380,11 @@ public:
[[nodiscard]] bool isCameraPaused() const; [[nodiscard]] bool isCameraPaused() const;
[[nodiscard]] const std::string &cameraSharingEndpoint() const; [[nodiscard]] const std::string &cameraSharingEndpoint() const;
[[nodiscard]] QString screenSharingDeviceId() const; [[nodiscard]] QString screenSharingDeviceId() const;
[[nodiscard]] bool screenSharingWithAudio() const;
void toggleVideo(bool active); void toggleVideo(bool active);
void toggleScreenSharing(std::optional<QString> uniqueId); void toggleScreenSharing(
std::optional<QString> uniqueId,
bool withAudio = false);
[[nodiscard]] bool hasVideoWithFrames() const; [[nodiscard]] bool hasVideoWithFrames() const;
[[nodiscard]] rpl::producer<bool> hasVideoWithFramesValue() const; [[nodiscard]] rpl::producer<bool> hasVideoWithFramesValue() const;
@ -614,6 +617,7 @@ private:
rpl::variable<Webrtc::VideoState> _screenState; rpl::variable<Webrtc::VideoState> _screenState;
rpl::variable<bool> _isSharingScreen = false; rpl::variable<bool> _isSharingScreen = false;
QString _screenDeviceId; QString _screenDeviceId;
bool _screenWithAudio = false;
base::flags<SendUpdateType> _pendingSelfUpdates; base::flags<SendUpdateType> _pendingSelfUpdates;
bool _requireARGB32 = true; bool _requireARGB32 = true;

View File

@ -260,12 +260,26 @@ QString Panel::chooseSourceActiveDeviceId() {
return _call->screenSharingDeviceId(); return _call->screenSharingDeviceId();
} }
bool Panel::chooseSourceActiveWithAudio() {
return _call->screenSharingWithAudio();
}
bool Panel::chooseSourceWithAudioSupported() {
#ifdef Q_OS_WIN
return true;
#else // Q_OS_WIN
return false;
#endif // Q_OS_WIN
}
rpl::lifetime &Panel::chooseSourceInstanceLifetime() { rpl::lifetime &Panel::chooseSourceInstanceLifetime() {
return lifetime(); return lifetime();
} }
void Panel::chooseSourceAccepted(const QString &deviceId) { void Panel::chooseSourceAccepted(
_call->toggleScreenSharing(deviceId); const QString &deviceId,
bool withAudio) {
_call->toggleScreenSharing(deviceId, withAudio);
} }
void Panel::chooseSourceStop() { void Panel::chooseSourceStop() {
@ -1185,7 +1199,7 @@ void Panel::chooseShareScreenSource() {
if (_call->isSharingScreen()) { if (_call->isSharingScreen()) {
_call->toggleScreenSharing(std::nullopt); _call->toggleScreenSharing(std::nullopt);
} else { } else {
chooseSourceAccepted(*source); chooseSourceAccepted(*source, false);
} }
} else { } else {
Ui::DesktopCapture::ChooseSource(this); Ui::DesktopCapture::ChooseSource(this);

View File

@ -169,8 +169,12 @@ private:
QWidget *chooseSourceParent() override; QWidget *chooseSourceParent() override;
QString chooseSourceActiveDeviceId() override; QString chooseSourceActiveDeviceId() override;
bool chooseSourceActiveWithAudio() override;
bool chooseSourceWithAudioSupported() override;
rpl::lifetime &chooseSourceInstanceLifetime() override; rpl::lifetime &chooseSourceInstanceLifetime() override;
void chooseSourceAccepted(const QString &deviceId) override; void chooseSourceAccepted(
const QString &deviceId,
bool withAudio) override;
void chooseSourceStop() override; void chooseSourceStop() override;
const not_null<GroupCall*> _call; const not_null<GroupCall*> _call;

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/checkbox.h"
#include "ui/effects/ripple_animation.h" #include "ui/effects/ripple_animation.h"
#include "ui/image/image.h" #include "ui/image/image.h"
#include "ui/platform/ui_platform_window_title.h" #include "ui/platform/ui_platform_window_title.h"
@ -62,6 +63,8 @@ public:
[[nodiscard]] rpl::producer<> activations() const; [[nodiscard]] rpl::producer<> activations() const;
void setActive(bool active); void setActive(bool active);
[[nodiscard]] bool isWindow() const;
[[nodiscard]] QString deviceIdKey() const;
[[nodiscard]] rpl::lifetime &lifetime(); [[nodiscard]] rpl::lifetime &lifetime();
private: private:
@ -94,6 +97,7 @@ private:
void setupGeometryWithParent(not_null<QWidget*> parent); void setupGeometryWithParent(not_null<QWidget*> parent);
void fillSources(); void fillSources();
void setupSourcesGeometry(); void setupSourcesGeometry();
void updateButtonsVisibility();
void destroy(); void destroy();
static base::flat_map< static base::flat_map<
@ -107,6 +111,7 @@ private:
const not_null<RpWidget*> _bottom; const not_null<RpWidget*> _bottom;
const not_null<RoundButton*> _submit; const not_null<RoundButton*> _submit;
const not_null<RoundButton*> _finish; const not_null<RoundButton*> _finish;
const not_null<Checkbox*> _withAudio;
std::vector<std::unique_ptr<Source>> _sources; std::vector<std::unique_ptr<Source>> _sources;
Source *_selected = nullptr; Source *_selected = nullptr;
@ -166,6 +171,14 @@ rpl::producer<> Source::activations() const {
return _activations.events(); return _activations.events();
} }
bool Source::isWindow() const {
return _source.isWindow();
}
QString Source::deviceIdKey() const {
return QString::fromStdString(_source.deviceIdKey());
}
void Source::setActive(bool active) { void Source::setActive(bool active) {
if (_active != active) { if (_active != active) {
_active = active; _active = active;
@ -255,7 +268,13 @@ ChooseSourceProcess::ChooseSourceProcess(
CreateChild<RoundButton>( CreateChild<RoundButton>(
_bottom.get(), _bottom.get(),
tr::lng_group_call_screen_share_stop(), tr::lng_group_call_screen_share_stop(),
st::desktopCaptureFinish)) { st::desktopCaptureFinish))
, _withAudio(
CreateChild<Checkbox>(
_bottom.get(),
tr::lng_group_call_screen_share_audio(tr::now),
false,
st::desktopCaptureWithAudio)) {
setupPanel(); setupPanel();
setupSources(); setupSources();
activate(); activate();
@ -336,7 +355,9 @@ void ChooseSourceProcess::setupPanel() {
return; return;
} }
const auto weak = MakeWeak(_window.get()); const auto weak = MakeWeak(_window.get());
_delegate->chooseSourceAccepted(_selectedId); _delegate->chooseSourceAccepted(
_selectedId,
!_withAudio->isHidden() && _withAudio->checked());
if (const auto strong = weak.data()) { if (const auto strong = weak.data()) {
strong->close(); strong->close();
} }
@ -375,6 +396,18 @@ void ChooseSourceProcess::setupPanel() {
bottomSkip); bottomSkip);
}, _bottom->lifetime()); }, _bottom->lifetime());
_withAudio->widthValue(
) | rpl::start_with_next([=](int width) {
const auto top = (bottomHeight - _withAudio->heightNoMargins()) / 2;
_withAudio->moveToLeft(bottomSkip, top);
}, _withAudio->lifetime());
_withAudio->setChecked(_delegate->chooseSourceActiveWithAudio());
_withAudio->checkedChanges(
) | rpl::start_with_next([=] {
updateButtonsVisibility();
}, _withAudio->lifetime());
const auto sharing = !_delegate->chooseSourceActiveDeviceId().isEmpty(); const auto sharing = !_delegate->chooseSourceActiveDeviceId().isEmpty();
_finish->setVisible(sharing); _finish->setVisible(sharing);
_submit->setVisible(!sharing); _submit->setVisible(!sharing);
@ -420,6 +453,8 @@ void ChooseSourceProcess::fillSources() {
auto screensManager = tgcalls::DesktopCaptureSourceManager(Type::Screen); auto screensManager = tgcalls::DesktopCaptureSourceManager(Type::Screen);
auto windowsManager = tgcalls::DesktopCaptureSourceManager(Type::Window); auto windowsManager = tgcalls::DesktopCaptureSourceManager(Type::Window);
_withAudio->setVisible(false);
auto screenIndex = 0; auto screenIndex = 0;
auto windowIndex = 0; auto windowIndex = 0;
const auto active = _delegate->chooseSourceActiveDeviceId(); const auto active = _delegate->chooseSourceActiveDeviceId();
@ -435,9 +470,13 @@ void ChooseSourceProcess::fillSources() {
const auto id = source.deviceIdKey(); const auto id = source.deviceIdKey();
_sources.push_back(std::make_unique<Source>(_inner, source, title)); _sources.push_back(std::make_unique<Source>(_inner, source, title));
const auto withAudioSupported = !source.isWindow()
&& _delegate->chooseSourceWithAudioSupported();
const auto raw = _sources.back().get(); const auto raw = _sources.back().get();
if (!active.isEmpty() && active.toStdString() == id) { if (!active.isEmpty() && active.toStdString() == id) {
_selected = raw; _selected = raw;
_withAudio->setVisible(withAudioSupported);
raw->setActive(true); raw->setActive(true);
} }
_sources.back()->activations( _sources.back()->activations(
@ -448,15 +487,8 @@ void ChooseSourceProcess::fillSources() {
_selected->setActive(false); _selected->setActive(false);
} }
_selected = raw; _selected = raw;
_selectedId = QString::fromStdString(id); _withAudio->setVisible(withAudioSupported);
if (_selectedId == _delegate->chooseSourceActiveDeviceId()) { updateButtonsVisibility();
_selectedId = QString();
_finish->setVisible(true);
_submit->setVisible(false);
} else {
_finish->setVisible(false);
_submit->setVisible(true);
}
}, raw->lifetime()); }, raw->lifetime());
}; };
for (const auto &source : screensManager.sources()) { for (const auto &source : screensManager.sources()) {
@ -467,6 +499,27 @@ void ChooseSourceProcess::fillSources() {
} }
} }
void ChooseSourceProcess::updateButtonsVisibility() {
const auto withAudioSupported = _selected
&& !_selected->isWindow()
&& _delegate->chooseSourceWithAudioSupported();
const auto selectedId = _selected
? _selected->deviceIdKey()
: QString();
if (selectedId == _delegate->chooseSourceActiveDeviceId()
&& (!withAudioSupported
|| (_withAudio->checked()
== _delegate->chooseSourceActiveWithAudio()))) {
_selectedId = QString();
_finish->setVisible(true);
_submit->setVisible(false);
} else {
_selectedId = selectedId;
_finish->setVisible(false);
_submit->setVisible(true);
}
}
void ChooseSourceProcess::setupSourcesGeometry() { void ChooseSourceProcess::setupSourcesGeometry() {
if (_sources.empty()) { if (_sources.empty()) {
destroy(); destroy();

View File

@ -20,8 +20,12 @@ class ChooseSourceDelegate {
public: public:
virtual QWidget *chooseSourceParent() = 0; virtual QWidget *chooseSourceParent() = 0;
virtual QString chooseSourceActiveDeviceId() = 0; virtual QString chooseSourceActiveDeviceId() = 0;
virtual bool chooseSourceActiveWithAudio() = 0;
virtual bool chooseSourceWithAudioSupported() = 0;
virtual rpl::lifetime &chooseSourceInstanceLifetime() = 0; virtual rpl::lifetime &chooseSourceInstanceLifetime() = 0;
virtual void chooseSourceAccepted(const QString &deviceId) = 0; virtual void chooseSourceAccepted(
const QString &deviceId,
bool withAudio) = 0;
virtual void chooseSourceStop() = 0; virtual void chooseSourceStop() = 0;
}; };

@ -1 +1 @@
Subproject commit 3cf1822a70e3b84f6a762755e5249b26e915d321 Subproject commit 07e0484a583121870316f3039aa2047ed030cd6d

View File

@ -49,9 +49,13 @@ PRIVATE
Message.h Message.h
NetworkManager.cpp NetworkManager.cpp
NetworkManager.h NetworkManager.h
SctpDataChannelProviderInterfaceImpl.cpp
SctpDataChannelProviderInterfaceImpl.h
StaticThreads.cpp StaticThreads.cpp
StaticThreads.h StaticThreads.h
ThreadLocalObject.h ThreadLocalObject.h
TurnCustomizerImpl.cpp
TurnCustomizerImpl.h
VideoCaptureInterface.cpp VideoCaptureInterface.cpp
VideoCaptureInterface.h VideoCaptureInterface.h
VideoCaptureInterfaceImpl.cpp VideoCaptureInterfaceImpl.cpp

@ -1 +1 @@
Subproject commit 5d16a97b57f0399d552e0c9dd72d27e81f6a8316 Subproject commit 3bd9b94e928b2ce963290d773926240ec2612d6a

View File

@ -110,9 +110,9 @@ Open **x64 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
cmake --build . --config Release cmake --build . --config Release
cd .. cd ..
git clone https://github.com/kcat/openal-soft.git git clone https://github.com/telegramdesktop/openal-soft.git
cd openal-soft cd openal-soft
git checkout openal-soft-1.21.0 git checkout wasapi_exact_device_time
cd build cd build
cmake .. ^ cmake .. ^
-G "Visual Studio 16 2019" ^ -G "Visual Studio 16 2019" ^

View File

@ -110,9 +110,9 @@ Open **x86 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
cmake --build . --config Release cmake --build . --config Release
cd .. cd ..
git clone https://github.com/kcat/openal-soft.git git clone https://github.com/telegramdesktop/openal-soft.git
cd openal-soft cd openal-soft
git checkout openal-soft-1.21.0 git checkout wasapi_exact_device_time
cd build cd build
cmake .. ^ cmake .. ^
-G "Visual Studio 16 2019" ^ -G "Visual Studio 16 2019" ^