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_incoming.mp3">../../sounds/call_incoming.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>
</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();
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;
}
}

View file

@ -62,15 +62,16 @@ public:
virtual void callFailed(not_null<Call*> call) = 0;
virtual void callRedial(not_null<Call*> 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<void()> onSuccess,
bool video) = 0;
virtual auto getVideoCapture()
-> std::shared_ptr<tgcalls::VideoCaptureInterface> = 0;

View file

@ -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,

View file

@ -61,6 +61,13 @@ public:
virtual void groupCallFailed(not_null<GroupCall*> call) = 0;
virtual void groupCallRequestPermissionsOrFail(
Fn<void()> 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*> _delegate;
@ -191,7 +202,8 @@ private:
std::shared_ptr<GlobalShortcutManager> _shortcutManager;
std::shared_ptr<GlobalShortcutValue> _pushToTalk;
base::Timer _pushToTalkCancelTimer;
bool _pushToTalkStarted = false;
base::Timer _connectingSoundTimer;
bool _hadJoinedState = false;
rpl::lifetime _lifetime;

View file

@ -98,35 +98,45 @@ void Instance::groupCallFailed(not_null<GroupCall*> 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<Media::Audio::Track*> 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*> call) {

View file

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

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