diff --git a/Telegram/Resources/qrc/telegram/sounds.qrc b/Telegram/Resources/qrc/telegram/sounds.qrc index 6135e0050..69d1427e5 100644 --- a/Telegram/Resources/qrc/telegram/sounds.qrc +++ b/Telegram/Resources/qrc/telegram/sounds.qrc @@ -6,5 +6,8 @@ ../../sounds/call_end.mp3 ../../sounds/call_incoming.mp3 ../../sounds/call_outgoing.mp3 + ../../sounds/group_call_start.mp3 + ../../sounds/group_call_connect.mp3 + ../../sounds/group_call_end.mp3 diff --git a/Telegram/Resources/sounds/group_call_connect.mp3 b/Telegram/Resources/sounds/group_call_connect.mp3 new file mode 100644 index 000000000..4e0f60b4f Binary files /dev/null and b/Telegram/Resources/sounds/group_call_connect.mp3 differ diff --git a/Telegram/Resources/sounds/group_call_end.mp3 b/Telegram/Resources/sounds/group_call_end.mp3 new file mode 100644 index 000000000..c03390958 Binary files /dev/null and b/Telegram/Resources/sounds/group_call_end.mp3 differ diff --git a/Telegram/Resources/sounds/group_call_start.mp3 b/Telegram/Resources/sounds/group_call_start.mp3 new file mode 100644 index 000000000..527959c9d Binary files /dev/null and b/Telegram/Resources/sounds/group_call_start.mp3 differ diff --git a/Telegram/SourceFiles/calls/calls_call.cpp b/Telegram/SourceFiles/calls/calls_call.cpp index 669d9153c..e78dbd8e9 100644 --- a/Telegram/SourceFiles/calls/calls_call.cpp +++ b/Telegram/SourceFiles/calls/calls_call.cpp @@ -951,20 +951,20 @@ void Call::setState(State state) { _startTime = crl::now(); break; case State::ExchangingKeys: - _delegate->playSound(Delegate::Sound::Connecting); + _delegate->callPlaySound(Delegate::CallSound::Connecting); break; case State::Ended: - _delegate->playSound(Delegate::Sound::Ended); + _delegate->callPlaySound(Delegate::CallSound::Ended); [[fallthrough]]; case State::EndedByOtherDevice: _delegate->callFinished(this); break; case State::Failed: - _delegate->playSound(Delegate::Sound::Ended); + _delegate->callPlaySound(Delegate::CallSound::Ended); _delegate->callFailed(this); break; case State::Busy: - _delegate->playSound(Delegate::Sound::Busy); + _delegate->callPlaySound(Delegate::CallSound::Busy); break; } } diff --git a/Telegram/SourceFiles/calls/calls_call.h b/Telegram/SourceFiles/calls/calls_call.h index 531397c1d..e4dcf2d65 100644 --- a/Telegram/SourceFiles/calls/calls_call.h +++ b/Telegram/SourceFiles/calls/calls_call.h @@ -62,15 +62,16 @@ public: virtual void callFailed(not_null call) = 0; virtual void callRedial(not_null call) = 0; - enum class Sound { + enum class CallSound { Connecting, Busy, Ended, }; - virtual void playSound(Sound sound) = 0; + virtual void callPlaySound(CallSound sound) = 0; virtual void callRequestPermissionsOrFail( Fn onSuccess, bool video) = 0; + virtual auto getVideoCapture() -> std::shared_ptr = 0; diff --git a/Telegram/SourceFiles/calls/calls_group_call.cpp b/Telegram/SourceFiles/calls/calls_group_call.cpp index 5ee162687..e705c4377 100644 --- a/Telegram/SourceFiles/calls/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/calls_group_call.cpp @@ -42,6 +42,7 @@ constexpr auto kMaxInvitePerSlice = 10; constexpr auto kCheckLastSpokeInterval = crl::time(1000); constexpr auto kCheckJoinedTimeout = 4 * crl::time(1000); constexpr auto kUpdateSendActionEach = crl::time(500); +constexpr auto kPlayConnectingEach = crl::time(1056) + 2 * crl::time(1000); } // namespace @@ -55,7 +56,8 @@ GroupCall::GroupCall( , _api(&peer->session().mtp()) , _lastSpokeCheckTimer([=] { checkLastSpoke(); }) , _checkJoinedTimer([=] { checkJoined(); }) -, _pushToTalkCancelTimer([=] { pushToTalkCancel(); }) { +, _pushToTalkCancelTimer([=] { pushToTalkCancel(); }) +, _connectingSoundTimer([=] { playConnectingSoundOnce(); }) { _muted.value( ) | rpl::combine_previous( ) | rpl::start_with_next([=](MuteState previous, MuteState state) { @@ -109,14 +111,22 @@ void GroupCall::setState(State state) { } _state = state; - if (_state.current() == State::Joined) { - if (!_pushToTalkStarted) { - _pushToTalkStarted = true; + if (state == State::Joined) { + stopConnectingSound(); + if (!_hadJoinedState) { + _hadJoinedState = true; applyGlobalShortcutChanges(); + _delegate->groupCallPlaySound(Delegate::GroupCallSound::Started); } if (const auto call = _peer->groupCall(); call && call->id() == _id) { call->setInCall(); } + } else if (state == State::Connecting || state == State::Joining) { + if (_hadJoinedState) { + playConnectingSound(); + } + } else { + stopConnectingSound(); } if (false @@ -127,6 +137,10 @@ void GroupCall::setState(State state) { destroyController(); } switch (state) { + case State::HangingUp: + case State::FailedHangingUp: + _delegate->groupCallPlaySound(Delegate::GroupCallSound::Ended); + break; case State::Ended: _delegate->groupCallFinished(this); break; @@ -141,6 +155,22 @@ void GroupCall::setState(State state) { } } +void GroupCall::playConnectingSound() { + if (_connectingSoundTimer.isActive()) { + return; + } + playConnectingSoundOnce(); + _connectingSoundTimer.callEach(kPlayConnectingEach); +} + +void GroupCall::stopConnectingSound() { + _connectingSoundTimer.cancel(); +} + +void GroupCall::playConnectingSoundOnce() { + _delegate->groupCallPlaySound(Delegate::GroupCallSound::Connecting); +} + void GroupCall::start() { _createRequestId = _api.request(MTPphone_CreateGroupCall( _peer->input, diff --git a/Telegram/SourceFiles/calls/calls_group_call.h b/Telegram/SourceFiles/calls/calls_group_call.h index 0ad338c41..8af623cee 100644 --- a/Telegram/SourceFiles/calls/calls_group_call.h +++ b/Telegram/SourceFiles/calls/calls_group_call.h @@ -61,6 +61,13 @@ public: virtual void groupCallFailed(not_null call) = 0; virtual void groupCallRequestPermissionsOrFail( Fn onSuccess) = 0; + + enum class GroupCallSound { + Started, + Connecting, + Ended, + }; + virtual void groupCallPlaySound(GroupCallSound sound) = 0; }; using GlobalShortcutManager = base::GlobalShortcutManager; @@ -162,6 +169,10 @@ private: void checkGlobalShortcutAvailability(); void checkJoined(); + void playConnectingSound(); + void stopConnectingSound(); + void playConnectingSoundOnce(); + [[nodiscard]] MTPInputGroupCall inputCall() const; const not_null _delegate; @@ -191,7 +202,8 @@ private: std::shared_ptr _shortcutManager; std::shared_ptr _pushToTalk; base::Timer _pushToTalkCancelTimer; - bool _pushToTalkStarted = false; + base::Timer _connectingSoundTimer; + bool _hadJoinedState = false; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/calls/calls_instance.cpp b/Telegram/SourceFiles/calls/calls_instance.cpp index 93ffbb202..7ce5ede23 100644 --- a/Telegram/SourceFiles/calls/calls_instance.cpp +++ b/Telegram/SourceFiles/calls/calls_instance.cpp @@ -98,35 +98,45 @@ void Instance::groupCallFailed(not_null call) { }); } -void Instance::playSound(Sound sound) { - switch (sound) { - case Sound::Busy: { - if (!_callBusyTrack) { - _callBusyTrack = Media::Audio::Current().createTrack(); - _callBusyTrack->fillFromFile( - Core::App().settings().getSoundPath(qsl("call_busy"))); - } - _callBusyTrack->playOnce(); - } break; - - case Sound::Ended: { - if (!_callEndedTrack) { - _callEndedTrack = Media::Audio::Current().createTrack(); - _callEndedTrack->fillFromFile( - Core::App().settings().getSoundPath(qsl("call_end"))); - } - _callEndedTrack->playOnce(); - } break; - - case Sound::Connecting: { - if (!_callConnectingTrack) { - _callConnectingTrack = Media::Audio::Current().createTrack(); - _callConnectingTrack->fillFromFile( - Core::App().settings().getSoundPath(qsl("call_connect"))); - } - _callConnectingTrack->playOnce(); - } break; +not_null Instance::ensureSoundLoaded( + const QString &key) { + const auto i = _tracks.find(key); + if (i != end(_tracks)) { + return i->second.get(); } + const auto result = _tracks.emplace( + key, + Media::Audio::Current().createTrack()).first->second.get(); + result->fillFromFile(Core::App().settings().getSoundPath(key)); + return result; +} + +void Instance::playSoundOnce(const QString &key) { + ensureSoundLoaded(key)->playOnce(); +} + +void Instance::callPlaySound(CallSound sound) { + playSoundOnce([&] { + switch (sound) { + case CallSound::Busy: return "call_busy"; + case CallSound::Ended: return "call_end"; + case CallSound::Connecting: return "call_connect"; + } + Unexpected("CallSound in Instance::callPlaySound."); + return ""; + }()); +} + +void Instance::groupCallPlaySound(GroupCallSound sound) { + playSoundOnce([&] { + switch (sound) { + case GroupCallSound::Started: return "group_call_start"; + case GroupCallSound::Ended: return "group_call_end"; + case GroupCallSound::Connecting: return "group_call_connect"; + } + Unexpected("GroupCallSound in Instance::groupCallPlaySound."); + return ""; + }()); } void Instance::destroyCall(not_null call) { diff --git a/Telegram/SourceFiles/calls/calls_instance.h b/Telegram/SourceFiles/calls/calls_instance.h index 0e2820800..73844d24f 100644 --- a/Telegram/SourceFiles/calls/calls_instance.h +++ b/Telegram/SourceFiles/calls/calls_instance.h @@ -64,6 +64,9 @@ public: [[nodiscard]] bool isQuitPrevent(); private: + using CallSound = Call::Delegate::CallSound; + using GroupCallSound = GroupCall::Delegate::GroupCallSound; + [[nodiscard]] not_null getCallDelegate() { return static_cast(this); } @@ -73,6 +76,10 @@ private: [[nodiscard]] DhConfig getDhConfig() const override { return _dhConfig; } + + not_null ensureSoundLoaded(const QString &key); + void playSoundOnce(const QString &key); + void callFinished(not_null call) override; void callFailed(not_null call) override; void callRedial(not_null call) override; @@ -81,15 +88,15 @@ private: bool video) override { requestPermissionsOrFail(std::move(onSuccess), video); } + void callPlaySound(CallSound sound) override; void groupCallFinished(not_null call) override; void groupCallFailed(not_null call) override; void groupCallRequestPermissionsOrFail(Fn onSuccess) override { requestPermissionsOrFail(std::move(onSuccess), false); } + void groupCallPlaySound(GroupCallSound sound) override; - using Sound = Call::Delegate::Sound; - void playSound(Sound sound) override; void createCall(not_null user, Call::Type type, bool video); void destroyCall(not_null call); @@ -98,7 +105,9 @@ private: const MTPInputGroupCall &inputCall); void destroyGroupCall(not_null call); - void requestPermissionOrFail(Platform::PermissionType type, Fn onSuccess); + void requestPermissionOrFail( + Platform::PermissionType type, + Fn onSuccess); void refreshDhConfig(); void refreshServerConfig(not_null session); @@ -132,9 +141,7 @@ private: rpl::event_stream _currentGroupCallChanges; std::unique_ptr _currentGroupCallPanel; - std::unique_ptr _callConnectingTrack; - std::unique_ptr _callEndedTrack; - std::unique_ptr _callBusyTrack; + base::flat_map> _tracks; }; diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 407079e5b..abb615a7c 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 407079e5b1cffdad2a08b0e00eafb78a175680c0 +Subproject commit abb615a7c9cb3a3992f67637592b481ccc50f17a