From 4672e3d0687849e3c169fa97ea3d79730c6b52f7 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 21 Aug 2020 14:50:13 +0400 Subject: [PATCH] Improve calls settings (camera / microphone). --- Telegram/SourceFiles/calls/calls_call.cpp | 15 +- Telegram/SourceFiles/calls/calls_call.h | 4 +- .../SourceFiles/settings/settings_calls.cpp | 289 ++++++++++-------- .../SourceFiles/settings/settings_calls.h | 13 +- Telegram/lib_webrtc | 2 +- 5 files changed, 186 insertions(+), 137 deletions(-) diff --git a/Telegram/SourceFiles/calls/calls_call.cpp b/Telegram/SourceFiles/calls/calls_call.cpp index 92ae77f610..a7b019363c 100644 --- a/Telegram/SourceFiles/calls/calls_call.cpp +++ b/Telegram/SourceFiles/calls/calls_call.cpp @@ -744,8 +744,8 @@ void Call::createAndStartController(const MTPDphoneCall &call) { .mediaDevicesConfig = tgcalls::MediaDevicesConfig{ .audioInputId = settings.callInputDeviceId().toStdString(), .audioOutputId = settings.callOutputDeviceId().toStdString(), - .inputVolume = settings.callInputVolume() / 100.f, - .outputVolume = settings.callOutputVolume() / 100.f, + .inputVolume = 1.f,//settings.callInputVolume() / 100.f, + .outputVolume = 1.f,//settings.callOutputVolume() / 100.f, }, .videoCapture = _videoCapture, .stateUpdated = [=](tgcalls::State state) { @@ -962,19 +962,20 @@ void Call::setState(State state) { } } -void Call::setCurrentAudioDevice(bool input, std::string deviceId) { +void Call::setCurrentAudioDevice(bool input, const QString &deviceId) { if (_instance) { + const auto id = deviceId.toStdString(); if (input) { - _instance->setAudioInputDevice(deviceId); + _instance->setAudioInputDevice(id); } else { - _instance->setAudioOutputDevice(deviceId); + _instance->setAudioOutputDevice(id); } } } -void Call::setCurrentVideoDevice(std::string deviceId) { +void Call::setCurrentVideoDevice(const QString &deviceId) { if (_videoCapture) { - _videoCapture->switchToDevice(deviceId); + _videoCapture->switchToDevice(deviceId.toStdString()); } } diff --git a/Telegram/SourceFiles/calls/calls_call.h b/Telegram/SourceFiles/calls/calls_call.h index 8411ac6c54..a8c42f24eb 100644 --- a/Telegram/SourceFiles/calls/calls_call.h +++ b/Telegram/SourceFiles/calls/calls_call.h @@ -172,8 +172,8 @@ public: QString getDebugLog() const; - void setCurrentAudioDevice(bool input, std::string deviceId); - void setCurrentVideoDevice(std::string deviceId); + void setCurrentAudioDevice(bool input, const QString &deviceId); + void setCurrentVideoDevice(const QString &deviceId); void setAudioVolume(bool input, float level); void setAudioDuckingEnabled(bool enabled); diff --git a/Telegram/SourceFiles/settings/settings_calls.cpp b/Telegram/SourceFiles/settings/settings_calls.cpp index db2f46df28..594e304360 100644 --- a/Telegram/SourceFiles/settings/settings_calls.cpp +++ b/Telegram/SourceFiles/settings/settings_calls.cpp @@ -26,22 +26,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/application.h" #include "core/core_settings.h" #include "calls/calls_instance.h" +#include "calls/calls_video_bubble.h" #include "webrtc/webrtc_media_devices.h" +#include "webrtc/webrtc_video_track.h" +#include "webrtc/webrtc_audio_input_tester.h" +#include "tgcalls/VideoCaptureInterface.h" #include "facades.h" - -#ifdef slots -#undef slots -#define NEED_TO_RESTORE_SLOTS -#endif // slots - -#include - -#ifdef NEED_TO_RESTORE_SLOTS -#define slots Q_SLOTS -#undef NEED_TO_RESTORE_SLOTS -#endif // NEED_TO_RESTORE_SLOTS +#include "styles/style_layers.h" namespace Settings { +namespace { + +constexpr auto kMicTestUpdateInterval = crl::time(100); +constexpr auto kMicTestAnimationDuration = crl::time(200); + +} // namespace Calls::Calls( QWidget *parent, @@ -49,6 +48,7 @@ Calls::Calls( : Section(parent) , _controller(controller) { setupContent(); + requestPermissionAndStartTestingMicrophone(); } Calls::~Calls() { @@ -99,6 +99,15 @@ void Calls::setupContent() { const auto cameras = Webrtc::GetVideoInputList(); if (!cameras.empty()) { + auto capturerOwner = tgcalls::VideoCaptureInterface::Create( + settings.callVideoInputDeviceId().toStdString()); + const auto capturer = capturerOwner.get(); + content->lifetime().add([owner = std::move(capturerOwner)]{}); + + const auto track = content->lifetime().make_state( + Webrtc::VideoState::Active); + capturer->setOutput(track->sink()); + const auto currentCameraName = [&] { const auto i = ranges::find( cameras, @@ -138,10 +147,11 @@ void Calls::setupContent() { const auto deviceId = option ? devices[option - 1].id : "default"; + capturer->switchToDevice(deviceId.toStdString()); Core::App().settings().setCallVideoInputDeviceId(deviceId); Core::App().saveSettingsDelayed(); if (const auto call = Core::App().calls().currentCall()) { - call->setCurrentVideoDevice(deviceId.toStdString()); + call->setCurrentVideoDevice(deviceId); } }); Ui::show(Box( @@ -150,6 +160,37 @@ void Calls::setupContent() { currentOption, save)); }); + const auto bubbleWrap = content->add(object_ptr(content)); + const auto bubble = content->lifetime().make_state<::Calls::VideoBubble>( + bubbleWrap, + track); + const auto padding = st::settingsButton.padding.left(); + const auto top = st::boxRoundShadow.extend.top(); + const auto bottom = st::boxRoundShadow.extend.bottom(); + + bubbleWrap->widthValue( + ) | rpl::filter([=](int width) { + return (width > 2 * padding + 1); + }) | rpl::start_with_next([=](int width) { + const auto use = (width - 2 * padding); + bubble->updateGeometry( + ::Calls::VideoBubble::DragMode::None, + QRect(padding, top, use, (use * 480) / 640)); + }, bubbleWrap->lifetime()); + + track->renderNextFrame( + ) | rpl::start_with_next([=] { + const auto size = track->frameSize(); + if (size.isEmpty()) { + return; + } + const auto width = bubbleWrap->width(); + const auto use = (width - 2 * padding); + bubbleWrap->resize( + width, + top + ((use * size.height()) / size.width()) + bottom); + bubbleWrap->update(); + }, bubbleWrap->lifetime()); AddSkip(content); AddDivider(content); @@ -186,7 +227,7 @@ void Calls::setupContent() { Core::App().settings().setCallOutputDeviceId(deviceId); Core::App().saveSettingsDelayed(); if (const auto call = Core::App().calls().currentCall()) { - call->setCurrentAudioDevice(false, deviceId.toStdString()); + call->setCurrentAudioDevice(false, deviceId); } }); Ui::show(Box( @@ -196,36 +237,36 @@ void Calls::setupContent() { save)); }); - const auto outputLabel = content->add( - object_ptr( - content, - st::settingsAudioVolumeLabel), - st::settingsAudioVolumeLabelPadding); - const auto outputSlider = content->add( - object_ptr( - content, - st::settingsAudioVolumeSlider), - st::settingsAudioVolumeSliderPadding); - const auto updateOutputLabel = [=](int value) { - const auto percent = QString::number(value); - outputLabel->setText( - tr::lng_settings_call_output_volume(tr::now, lt_percent, percent)); - }; - const auto updateOutputVolume = [=](int value) { - _needWriteSettings = true; - updateOutputLabel(value); - Core::App().settings().setCallOutputVolume(value); - if (const auto call = Core::App().calls().currentCall()) { - call->setAudioVolume(false, value / 100.0f); - } - }; - outputSlider->resize(st::settingsAudioVolumeSlider.seekSize); - outputSlider->setPseudoDiscrete( - 101, - [](int val) { return val; }, - settings.callOutputVolume(), - updateOutputVolume); - updateOutputLabel(Core::App().settings().callOutputVolume()); + //const auto outputLabel = content->add( + // object_ptr( + // content, + // st::settingsAudioVolumeLabel), + // st::settingsAudioVolumeLabelPadding); + //const auto outputSlider = content->add( + // object_ptr( + // content, + // st::settingsAudioVolumeSlider), + // st::settingsAudioVolumeSliderPadding); + //const auto updateOutputLabel = [=](int value) { + // const auto percent = QString::number(value); + // outputLabel->setText( + // tr::lng_settings_call_output_volume(tr::now, lt_percent, percent)); + //}; + //const auto updateOutputVolume = [=](int value) { + // _needWriteSettings = true; + // updateOutputLabel(value); + // Core::App().settings().setCallOutputVolume(value); + // if (const auto call = Core::App().calls().currentCall()) { + // call->setAudioVolume(false, value / 100.0f); + // } + //}; + //outputSlider->resize(st::settingsAudioVolumeSlider.seekSize); + //outputSlider->setPseudoDiscrete( + // 101, + // [](int val) { return val; }, + // settings.callOutputVolume(), + // updateOutputVolume); + //updateOutputLabel(Core::App().settings().callOutputVolume()); AddSkip(content); AddDivider(content); @@ -261,10 +302,10 @@ void Calls::setupContent() { Core::App().settings().setCallInputDeviceId(deviceId); Core::App().saveSettingsDelayed(); if (_micTester) { - stopTestingMicrophone(); + _micTester->setDeviceId(deviceId); } if (const auto call = Core::App().calls().currentCall()) { - call->setCurrentAudioDevice(true, deviceId.toStdString()); + call->setCurrentAudioDevice(true, deviceId); } }); Ui::show(Box( @@ -274,51 +315,51 @@ void Calls::setupContent() { save)); }); - const auto inputLabel = content->add( - object_ptr( - content, - st::settingsAudioVolumeLabel), - st::settingsAudioVolumeLabelPadding); - const auto inputSlider = content->add( - object_ptr( - content, - st::settingsAudioVolumeSlider), - st::settingsAudioVolumeSliderPadding); - const auto updateInputLabel = [=](int value) { - const auto percent = QString::number(value); - inputLabel->setText( - tr::lng_settings_call_input_volume(tr::now, lt_percent, percent)); - }; - const auto updateInputVolume = [=](int value) { - _needWriteSettings = true; - updateInputLabel(value); - Core::App().settings().setCallInputVolume(value); - if (const auto call = Core::App().calls().currentCall()) { - call->setAudioVolume(true, value / 100.0f); - } - }; - inputSlider->resize(st::settingsAudioVolumeSlider.seekSize); - inputSlider->setPseudoDiscrete(101, - [](int val) { return val; }, - settings.callInputVolume(), - updateInputVolume); - updateInputLabel(settings.callInputVolume()); + //const auto inputLabel = content->add( + // object_ptr( + // content, + // st::settingsAudioVolumeLabel), + // st::settingsAudioVolumeLabelPadding); + //const auto inputSlider = content->add( + // object_ptr( + // content, + // st::settingsAudioVolumeSlider), + // st::settingsAudioVolumeSliderPadding); + //const auto updateInputLabel = [=](int value) { + // const auto percent = QString::number(value); + // inputLabel->setText( + // tr::lng_settings_call_input_volume(tr::now, lt_percent, percent)); + //}; + //const auto updateInputVolume = [=](int value) { + // _needWriteSettings = true; + // updateInputLabel(value); + // Core::App().settings().setCallInputVolume(value); + // if (const auto call = Core::App().calls().currentCall()) { + // call->setAudioVolume(true, value / 100.0f); + // } + //}; + //inputSlider->resize(st::settingsAudioVolumeSlider.seekSize); + //inputSlider->setPseudoDiscrete(101, + // [](int val) { return val; }, + // settings.callInputVolume(), + // updateInputVolume); + //updateInputLabel(settings.callInputVolume()); - AddButton( - content, - rpl::single( - tr::lng_settings_call_test_mic(tr::now) - ) | rpl::then( - _micTestTextStream.events() - ), - st::settingsButton - )->addClickHandler([=] { - if (!_micTester) { - requestPermissionAndStartTestingMicrophone(); - } else { - stopTestingMicrophone(); - } - }); + //AddButton( + // content, + // rpl::single( + // tr::lng_settings_call_test_mic(tr::now) + // ) | rpl::then( + // _micTestTextStream.events() + // ), + // st::settingsButton + //)->addClickHandler([=] { + // if (!_micTester) { + // requestPermissionAndStartTestingMicrophone(); + // } else { + // stopTestingMicrophone(); + // } + //}); _micTestLevel = content->add( object_ptr( @@ -328,7 +369,11 @@ void Calls::setupContent() { _micTestLevel->resize(QSize(0, st::defaultLevelMeter.height)); _levelUpdateTimer.setCallback([=] { - _micTestLevel->setValue(_micTester->GetAndResetLevel()); + const auto was = _micLevel; + _micLevel = _micTester->getAndResetLevel(); + _micLevelAnimation.start([=] { + _micTestLevel->setValue(_micLevelAnimation.value(_micLevel)); + }, was, _micLevel, kMicTestAnimationDuration); }); AddSkip(content); @@ -336,23 +381,23 @@ void Calls::setupContent() { AddSkip(content); AddSubsectionTitle(content, tr::lng_settings_call_section_other()); -#if defined Q_OS_MAC && !defined OS_MAC_STORE - AddButton( - content, - tr::lng_settings_call_audio_ducking(), - st::settingsButton - )->toggleOn( - rpl::single(settings.callAudioDuckingEnabled()) - )->toggledValue() | rpl::filter([](bool enabled) { - return (enabled != Core::App().settings().callAudioDuckingEnabled()); - }) | rpl::start_with_next([=](bool enabled) { - Core::App().settings().setCallAudioDuckingEnabled(enabled); - Core::App().saveSettingsDelayed(); - if (const auto call = Core::App().calls().currentCall()) { - call->setAudioDuckingEnabled(enabled); - } - }, content->lifetime()); -#endif // Q_OS_MAC && !OS_MAC_STORE +//#if defined Q_OS_MAC && !defined OS_MAC_STORE +// AddButton( +// content, +// tr::lng_settings_call_audio_ducking(), +// st::settingsButton +// )->toggleOn( +// rpl::single(settings.callAudioDuckingEnabled()) +// )->toggledValue() | rpl::filter([](bool enabled) { +// return (enabled != Core::App().settings().callAudioDuckingEnabled()); +// }) | rpl::start_with_next([=](bool enabled) { +// Core::App().settings().setCallAudioDuckingEnabled(enabled); +// Core::App().saveSettingsDelayed(); +// if (const auto call = Core::App().calls().currentCall()) { +// call->setAudioDuckingEnabled(enabled); +// } +// }, content->lifetime()); +//#endif // Q_OS_MAC && !OS_MAC_STORE AddButton( content, @@ -401,22 +446,22 @@ void Calls::requestPermissionAndStartTestingMicrophone() { } void Calls::startTestingMicrophone() { - _micTestTextStream.fire(tr::lng_settings_call_stop_mic_test(tr::now)); - _levelUpdateTimer.callEach(50); - _micTester = std::make_unique( - Core::App().settings().callInputDeviceId().toStdString()); - if (_micTester->Failed()) { - stopTestingMicrophone(); - Ui::show(Box(tr::lng_call_error_audio_io(tr::now))); - } + //_micTestTextStream.fire(tr::lng_settings_call_stop_mic_test(tr::now)); + _levelUpdateTimer.callEach(kMicTestUpdateInterval); + _micTester = std::make_unique( + Core::App().settings().callInputDeviceId()); + //if (_micTester->Failed()) { + // stopTestingMicrophone(); + // Ui::show(Box(tr::lng_call_error_audio_io(tr::now))); + //} } -void Calls::stopTestingMicrophone() { - _micTestTextStream.fire(tr::lng_settings_call_test_mic(tr::now)); - _levelUpdateTimer.cancel(); - _micTester.reset(); - _micTestLevel->setValue(0.0f); -} +//void Calls::stopTestingMicrophone() { +// _micTestTextStream.fire(tr::lng_settings_call_test_mic(tr::now)); +// _levelUpdateTimer.cancel(); +// _micTester.reset(); +// _micTestLevel->setValue(0.0f); +//} } // namespace Settings diff --git a/Telegram/SourceFiles/settings/settings_calls.h b/Telegram/SourceFiles/settings/settings_calls.h index b6570bd80b..fdb5949d69 100644 --- a/Telegram/SourceFiles/settings/settings_calls.h +++ b/Telegram/SourceFiles/settings/settings_calls.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "settings/settings_common.h" +#include "ui/effects/animations.h" #include "base/timer.h" namespace Calls { @@ -18,9 +19,9 @@ namespace Ui { class LevelMeter; } // namespace Ui -namespace tgvoip { +namespace Webrtc { class AudioInputTester; -} // namespace tgvoip +} // namespace Webrtc namespace Settings { @@ -35,16 +36,18 @@ private: void setupContent(); void requestPermissionAndStartTestingMicrophone(); void startTestingMicrophone(); - void stopTestingMicrophone(); + //void stopTestingMicrophone(); const not_null _controller; rpl::event_stream _cameraNameStream; rpl::event_stream _outputNameStream; rpl::event_stream _inputNameStream; - rpl::event_stream _micTestTextStream; + //rpl::event_stream _micTestTextStream; bool _needWriteSettings = false; - std::unique_ptr _micTester; + std::unique_ptr _micTester; Ui::LevelMeter *_micTestLevel = nullptr; + float _micLevel = 0.; + Ui::Animations::Simple _micLevelAnimation; base::Timer _levelUpdateTimer; }; diff --git a/Telegram/lib_webrtc b/Telegram/lib_webrtc index 48988791c0..8a83223c5e 160000 --- a/Telegram/lib_webrtc +++ b/Telegram/lib_webrtc @@ -1 +1 @@ -Subproject commit 48988791c082648d9876cc0e734db33af1440c02 +Subproject commit 8a83223c5e3133e5470a633fb9ac188d60f44b84