Add start/end/reconnecting sounds to voice chats.

This commit is contained in:
John Preston 2020-12-18 12:44:19 +04:00
parent d301601360
commit c5ad7c7c89
11 changed files with 109 additions and 46 deletions

View file

@ -6,5 +6,8 @@
<file alias="call_end.mp3">../../sounds/call_end.mp3</file> <file alias="call_end.mp3">../../sounds/call_end.mp3</file>
<file alias="call_incoming.mp3">../../sounds/call_incoming.mp3</file> <file alias="call_incoming.mp3">../../sounds/call_incoming.mp3</file>
<file alias="call_outgoing.mp3">../../sounds/call_outgoing.mp3</file> <file alias="call_outgoing.mp3">../../sounds/call_outgoing.mp3</file>
<file alias="group_call_start.mp3">../../sounds/group_call_start.mp3</file>
<file alias="group_call_connect.mp3">../../sounds/group_call_connect.mp3</file>
<file alias="group_call_end.mp3">../../sounds/group_call_end.mp3</file>
</qresource> </qresource>
</RCC> </RCC>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -951,20 +951,20 @@ void Call::setState(State state) {
_startTime = crl::now(); _startTime = crl::now();
break; break;
case State::ExchangingKeys: case State::ExchangingKeys:
_delegate->playSound(Delegate::Sound::Connecting); _delegate->callPlaySound(Delegate::CallSound::Connecting);
break; break;
case State::Ended: case State::Ended:
_delegate->playSound(Delegate::Sound::Ended); _delegate->callPlaySound(Delegate::CallSound::Ended);
[[fallthrough]]; [[fallthrough]];
case State::EndedByOtherDevice: case State::EndedByOtherDevice:
_delegate->callFinished(this); _delegate->callFinished(this);
break; break;
case State::Failed: case State::Failed:
_delegate->playSound(Delegate::Sound::Ended); _delegate->callPlaySound(Delegate::CallSound::Ended);
_delegate->callFailed(this); _delegate->callFailed(this);
break; break;
case State::Busy: case State::Busy:
_delegate->playSound(Delegate::Sound::Busy); _delegate->callPlaySound(Delegate::CallSound::Busy);
break; break;
} }
} }

View file

@ -62,15 +62,16 @@ public:
virtual void callFailed(not_null<Call*> call) = 0; virtual void callFailed(not_null<Call*> call) = 0;
virtual void callRedial(not_null<Call*> call) = 0; virtual void callRedial(not_null<Call*> call) = 0;
enum class Sound { enum class CallSound {
Connecting, Connecting,
Busy, Busy,
Ended, Ended,
}; };
virtual void playSound(Sound sound) = 0; virtual void callPlaySound(CallSound sound) = 0;
virtual void callRequestPermissionsOrFail( virtual void callRequestPermissionsOrFail(
Fn<void()> onSuccess, Fn<void()> onSuccess,
bool video) = 0; bool video) = 0;
virtual auto getVideoCapture() virtual auto getVideoCapture()
-> std::shared_ptr<tgcalls::VideoCaptureInterface> = 0; -> std::shared_ptr<tgcalls::VideoCaptureInterface> = 0;

View file

@ -42,6 +42,7 @@ constexpr auto kMaxInvitePerSlice = 10;
constexpr auto kCheckLastSpokeInterval = crl::time(1000); constexpr auto kCheckLastSpokeInterval = crl::time(1000);
constexpr auto kCheckJoinedTimeout = 4 * crl::time(1000); constexpr auto kCheckJoinedTimeout = 4 * crl::time(1000);
constexpr auto kUpdateSendActionEach = crl::time(500); constexpr auto kUpdateSendActionEach = crl::time(500);
constexpr auto kPlayConnectingEach = crl::time(1056) + 2 * crl::time(1000);
} // namespace } // namespace
@ -55,7 +56,8 @@ GroupCall::GroupCall(
, _api(&peer->session().mtp()) , _api(&peer->session().mtp())
, _lastSpokeCheckTimer([=] { checkLastSpoke(); }) , _lastSpokeCheckTimer([=] { checkLastSpoke(); })
, _checkJoinedTimer([=] { checkJoined(); }) , _checkJoinedTimer([=] { checkJoined(); })
, _pushToTalkCancelTimer([=] { pushToTalkCancel(); }) { , _pushToTalkCancelTimer([=] { pushToTalkCancel(); })
, _connectingSoundTimer([=] { playConnectingSoundOnce(); }) {
_muted.value( _muted.value(
) | rpl::combine_previous( ) | rpl::combine_previous(
) | rpl::start_with_next([=](MuteState previous, MuteState state) { ) | rpl::start_with_next([=](MuteState previous, MuteState state) {
@ -109,14 +111,22 @@ void GroupCall::setState(State state) {
} }
_state = state; _state = state;
if (_state.current() == State::Joined) { if (state == State::Joined) {
if (!_pushToTalkStarted) { stopConnectingSound();
_pushToTalkStarted = true; if (!_hadJoinedState) {
_hadJoinedState = true;
applyGlobalShortcutChanges(); applyGlobalShortcutChanges();
_delegate->groupCallPlaySound(Delegate::GroupCallSound::Started);
} }
if (const auto call = _peer->groupCall(); call && call->id() == _id) { if (const auto call = _peer->groupCall(); call && call->id() == _id) {
call->setInCall(); call->setInCall();
} }
} else if (state == State::Connecting || state == State::Joining) {
if (_hadJoinedState) {
playConnectingSound();
}
} else {
stopConnectingSound();
} }
if (false if (false
@ -127,6 +137,10 @@ void GroupCall::setState(State state) {
destroyController(); destroyController();
} }
switch (state) { switch (state) {
case State::HangingUp:
case State::FailedHangingUp:
_delegate->groupCallPlaySound(Delegate::GroupCallSound::Ended);
break;
case State::Ended: case State::Ended:
_delegate->groupCallFinished(this); _delegate->groupCallFinished(this);
break; 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() { void GroupCall::start() {
_createRequestId = _api.request(MTPphone_CreateGroupCall( _createRequestId = _api.request(MTPphone_CreateGroupCall(
_peer->input, _peer->input,

View file

@ -61,6 +61,13 @@ public:
virtual void groupCallFailed(not_null<GroupCall*> call) = 0; virtual void groupCallFailed(not_null<GroupCall*> call) = 0;
virtual void groupCallRequestPermissionsOrFail( virtual void groupCallRequestPermissionsOrFail(
Fn<void()> onSuccess) = 0; Fn<void()> onSuccess) = 0;
enum class GroupCallSound {
Started,
Connecting,
Ended,
};
virtual void groupCallPlaySound(GroupCallSound sound) = 0;
}; };
using GlobalShortcutManager = base::GlobalShortcutManager; using GlobalShortcutManager = base::GlobalShortcutManager;
@ -162,6 +169,10 @@ private:
void checkGlobalShortcutAvailability(); void checkGlobalShortcutAvailability();
void checkJoined(); void checkJoined();
void playConnectingSound();
void stopConnectingSound();
void playConnectingSoundOnce();
[[nodiscard]] MTPInputGroupCall inputCall() const; [[nodiscard]] MTPInputGroupCall inputCall() const;
const not_null<Delegate*> _delegate; const not_null<Delegate*> _delegate;
@ -191,7 +202,8 @@ private:
std::shared_ptr<GlobalShortcutManager> _shortcutManager; std::shared_ptr<GlobalShortcutManager> _shortcutManager;
std::shared_ptr<GlobalShortcutValue> _pushToTalk; std::shared_ptr<GlobalShortcutValue> _pushToTalk;
base::Timer _pushToTalkCancelTimer; base::Timer _pushToTalkCancelTimer;
bool _pushToTalkStarted = false; base::Timer _connectingSoundTimer;
bool _hadJoinedState = false;
rpl::lifetime _lifetime; rpl::lifetime _lifetime;

View file

@ -98,35 +98,45 @@ void Instance::groupCallFailed(not_null<GroupCall*> call) {
}); });
} }
void Instance::playSound(Sound sound) { not_null<Media::Audio::Track*> Instance::ensureSoundLoaded(
switch (sound) { const QString &key) {
case Sound::Busy: { const auto i = _tracks.find(key);
if (!_callBusyTrack) { if (i != end(_tracks)) {
_callBusyTrack = Media::Audio::Current().createTrack(); return i->second.get();
_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;
} }
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*> call) { void Instance::destroyCall(not_null<Call*> call) {

View file

@ -64,6 +64,9 @@ public:
[[nodiscard]] bool isQuitPrevent(); [[nodiscard]] bool isQuitPrevent();
private: private:
using CallSound = Call::Delegate::CallSound;
using GroupCallSound = GroupCall::Delegate::GroupCallSound;
[[nodiscard]] not_null<Call::Delegate*> getCallDelegate() { [[nodiscard]] not_null<Call::Delegate*> getCallDelegate() {
return static_cast<Call::Delegate*>(this); return static_cast<Call::Delegate*>(this);
} }
@ -73,6 +76,10 @@ private:
[[nodiscard]] DhConfig getDhConfig() const override { [[nodiscard]] DhConfig getDhConfig() const override {
return _dhConfig; return _dhConfig;
} }
not_null<Media::Audio::Track*> ensureSoundLoaded(const QString &key);
void playSoundOnce(const QString &key);
void callFinished(not_null<Call*> call) override; void callFinished(not_null<Call*> call) override;
void callFailed(not_null<Call*> call) override; void callFailed(not_null<Call*> call) override;
void callRedial(not_null<Call*> call) override; void callRedial(not_null<Call*> call) override;
@ -81,15 +88,15 @@ private:
bool video) override { bool video) override {
requestPermissionsOrFail(std::move(onSuccess), video); requestPermissionsOrFail(std::move(onSuccess), video);
} }
void callPlaySound(CallSound sound) override;
void groupCallFinished(not_null<GroupCall*> call) override; void groupCallFinished(not_null<GroupCall*> call) override;
void groupCallFailed(not_null<GroupCall*> call) override; void groupCallFailed(not_null<GroupCall*> call) override;
void groupCallRequestPermissionsOrFail(Fn<void()> onSuccess) override { void groupCallRequestPermissionsOrFail(Fn<void()> onSuccess) override {
requestPermissionsOrFail(std::move(onSuccess), false); requestPermissionsOrFail(std::move(onSuccess), false);
} }
void groupCallPlaySound(GroupCallSound sound) override;
using Sound = Call::Delegate::Sound;
void playSound(Sound sound) override;
void createCall(not_null<UserData*> user, Call::Type type, bool video); void createCall(not_null<UserData*> user, Call::Type type, bool video);
void destroyCall(not_null<Call*> call); void destroyCall(not_null<Call*> call);
@ -98,7 +105,9 @@ private:
const MTPInputGroupCall &inputCall); const MTPInputGroupCall &inputCall);
void destroyGroupCall(not_null<GroupCall*> call); void destroyGroupCall(not_null<GroupCall*> call);
void requestPermissionOrFail(Platform::PermissionType type, Fn<void()> onSuccess); void requestPermissionOrFail(
Platform::PermissionType type,
Fn<void()> onSuccess);
void refreshDhConfig(); void refreshDhConfig();
void refreshServerConfig(not_null<Main::Session*> session); void refreshServerConfig(not_null<Main::Session*> session);
@ -132,9 +141,7 @@ private:
rpl::event_stream<GroupCall*> _currentGroupCallChanges; rpl::event_stream<GroupCall*> _currentGroupCallChanges;
std::unique_ptr<GroupPanel> _currentGroupCallPanel; std::unique_ptr<GroupPanel> _currentGroupCallPanel;
std::unique_ptr<Media::Audio::Track> _callConnectingTrack; base::flat_map<QString, std::unique_ptr<Media::Audio::Track>> _tracks;
std::unique_ptr<Media::Audio::Track> _callEndedTrack;
std::unique_ptr<Media::Audio::Track> _callBusyTrack;
}; };

@ -1 +1 @@
Subproject commit 407079e5b1cffdad2a08b0e00eafb78a175680c0 Subproject commit abb615a7c9cb3a3992f67637592b481ccc50f17a