Use TgVoip interface instead of VoIPController.

This commit is contained in:
John Preston 2020-05-14 18:12:07 +04:00
parent c967a72dcb
commit ea4044e38c
6 changed files with 313 additions and 186 deletions

View File

@ -264,6 +264,9 @@ PRIVATE
calls/calls_box_controller.h calls/calls_box_controller.h
calls/calls_call.cpp calls/calls_call.cpp
calls/calls_call.h calls/calls_call.h
calls/calls_controller.cpp
calls/calls_controller.h
calls/calls_controller_tgvoip.h
calls/calls_emoji_fingerprint.cpp calls/calls_emoji_fingerprint.cpp
calls/calls_emoji_fingerprint.h calls/calls_emoji_fingerprint.h
calls/calls_instance.cpp calls/calls_instance.cpp

View File

@ -18,23 +18,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/audio/media_audio_track.h" #include "media/audio/media_audio_track.h"
#include "base/platform/base_platform_info.h" #include "base/platform/base_platform_info.h"
#include "calls/calls_panel.h" #include "calls/calls_panel.h"
#include "calls/calls_controller.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "facades.h" #include "facades.h"
#ifdef slots
#undef slots
#define NEED_TO_RESTORE_SLOTS
#endif // slots
#include <VoIPController.h>
#include <VoIPServerConfig.h>
#ifdef NEED_TO_RESTORE_SLOTS
#define slots Q_SLOTS
#undef NEED_TO_RESTORE_SLOTS
#endif // NEED_TO_RESTORE_SLOTS
namespace Calls { namespace Calls {
namespace { namespace {
@ -43,25 +31,25 @@ constexpr auto kHangupTimeoutMs = 5000;
constexpr auto kSha256Size = 32; constexpr auto kSha256Size = 32;
void AppendEndpoint( void AppendEndpoint(
std::vector<tgvoip::Endpoint> &list, std::vector<TgVoipEndpoint> &list,
const MTPPhoneConnection &connection) { const MTPPhoneConnection &connection) {
connection.match([&](const MTPDphoneConnection &data) { connection.match([&](const MTPDphoneConnection &data) {
if (data.vpeer_tag().v.length() != 16) { if (data.vpeer_tag().v.length() != 16) {
return; return;
} }
const auto ipv4 = tgvoip::IPv4Address(std::string( auto endpoint = TgVoipEndpoint{
data.vip().v.constData(), .endpointId = (int64_t)data.vid().v,
data.vip().v.size())); .host = TgVoipEdpointHost{
const auto ipv6 = tgvoip::IPv6Address(std::string( .ipv4 = data.vip().v.toStdString(),
data.vipv6().v.constData(), .ipv6 = data.vipv6().v.toStdString() },
data.vipv6().v.size())); .port = (uint16_t)data.vport().v,
list.emplace_back( .type = TgVoipEndpointType::UdpRelay
(int64_t)data.vid().v, };
(uint16_t)data.vport().v, const auto tag = data.vpeer_tag().v;
ipv4, if (tag.size() >= 16) {
ipv6, memcpy(endpoint.peerTag, tag.data(), 16);
tgvoip::Endpoint::Type::UDP_RELAY, }
(unsigned char*)data.vpeer_tag().v.data()); list.push_back(std::move(endpoint));
}); });
} }
@ -80,47 +68,25 @@ uint64 ComputeFingerprint(bytes::const_span authKey) {
| (gsl::to_integer<uint64>(hash[12])); | (gsl::to_integer<uint64>(hash[12]));
} }
} // namespace [[nodiscard]] std::vector<std::string> CollectVersions() {
return { TgVoip::getVersion() };
void Call::ControllerPointer::create() {
Expects(_data == nullptr);
_data = std::make_unique<tgvoip::VoIPController>();
} }
void Call::ControllerPointer::reset() { [[nodiscard]] QVector<MTPstring> WrapVersions(
if (const auto controller = base::take(_data)) { const std::vector<std::string> &data) {
controller->Stop(); auto result = QVector<MTPstring>();
result.reserve(data.size());
for (const auto &version : data) {
result.push_back(MTP_string(version));
} }
return result;
} }
bool Call::ControllerPointer::empty() const { [[nodiscard]] QVector<MTPstring> CollectVersionsForApi() {
return (_data == nullptr); return WrapVersions(CollectVersions());
} }
bool Call::ControllerPointer::operator==(std::nullptr_t) const { } // namespace
return empty();
}
Call::ControllerPointer::operator bool() const {
return !empty();
}
tgvoip::VoIPController *Call::ControllerPointer::operator->() const {
Expects(!empty());
return _data.get();
}
tgvoip::VoIPController &Call::ControllerPointer::operator*() const {
Expects(!empty());
return *_data;
}
Call::ControllerPointer::~ControllerPointer() {
reset();
}
Call::Delegate::~Delegate() = default; Call::Delegate::~Delegate() = default;
@ -199,8 +165,8 @@ void Call::startOutgoing() {
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
| MTPDphoneCallProtocol::Flag::f_udp_reflector), | MTPDphoneCallProtocol::Flag::f_udp_reflector),
MTP_int(kMinLayer), MTP_int(kMinLayer),
MTP_int(tgvoip::VoIPController::GetConnectionMaxLayer()), MTP_int(TgVoip::getConnectionMaxLayer()),
MTP_vector(1, MTP_string("2.4.4"))) MTP_vector(CollectVersionsForApi()))
)).done([=](const MTPphone_PhoneCall &result) { )).done([=](const MTPphone_PhoneCall &result) {
Expects(result.type() == mtpc_phone_phoneCall); Expects(result.type() == mtpc_phone_phoneCall);
@ -278,8 +244,8 @@ void Call::actuallyAnswer() {
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
| MTPDphoneCallProtocol::Flag::f_udp_reflector), | MTPDphoneCallProtocol::Flag::f_udp_reflector),
MTP_int(kMinLayer), MTP_int(kMinLayer),
MTP_int(tgvoip::VoIPController::GetConnectionMaxLayer()), MTP_int(TgVoip::getConnectionMaxLayer()),
MTP_vector(1, MTP_string("2.4.4"))) MTP_vector(CollectVersionsForApi()))
)).done([=](const MTPphone_PhoneCall &result) { )).done([=](const MTPphone_PhoneCall &result) {
Expects(result.type() == mtpc_phone_phoneCall); Expects(result.type() == mtpc_phone_phoneCall);
auto &call = result.c_phone_phoneCall(); auto &call = result.c_phone_phoneCall();
@ -300,7 +266,7 @@ void Call::actuallyAnswer() {
void Call::setMute(bool mute) { void Call::setMute(bool mute) {
_mute = mute; _mute = mute;
if (_controller) { if (_controller) {
_controller->SetMicMute(_mute); _controller->setMuteMicrophone(_mute);
} }
_muteChanged.notify(_mute); _muteChanged.notify(_mute);
} }
@ -334,8 +300,7 @@ void Call::redial() {
} }
QString Call::getDebugLog() const { QString Call::getDebugLog() const {
const auto debug = _controller->GetDebugString(); return QString::fromStdString(_controller->getDebugInfo());
return QString::fromUtf8(debug.data(), debug.size());
} }
void Call::startWaitingTrack() { void Call::startWaitingTrack() {
@ -441,7 +406,9 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
return false; return false;
} }
if (data.is_need_debug()) { if (data.is_need_debug()) {
auto debugLog = _controller ? _controller->GetDebugLog() : std::string(); auto debugLog = _controller
? _controller->getDebugInfo()
: std::string();
if (!debugLog.empty()) { if (!debugLog.empty()) {
MTP::send( MTP::send(
MTPphone_SaveCallDebug( MTPphone_SaveCallDebug(
@ -517,8 +484,8 @@ void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) {
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
| MTPDphoneCallProtocol::Flag::f_udp_reflector), | MTPDphoneCallProtocol::Flag::f_udp_reflector),
MTP_int(kMinLayer), MTP_int(kMinLayer),
MTP_int(tgvoip::VoIPController::GetConnectionMaxLayer()), MTP_int(TgVoip::getConnectionMaxLayer()),
MTP_vector(1, MTP_string("2.4.4"))) MTP_vector(CollectVersionsForApi()))
)).done([this](const MTPphone_PhoneCall &result) { )).done([this](const MTPphone_PhoneCall &result) {
Expects(result.type() == mtpc_phone_phoneCall); Expects(result.type() == mtpc_phone_phoneCall);
@ -566,126 +533,123 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
return; return;
} }
tgvoip::VoIPController::Config config; const auto &protocol = call.vprotocol().c_phoneCallProtocol();
config.dataSaving = tgvoip::DATA_SAVING_NEVER;
TgVoipConfig config;
config.dataSaving = TgVoipDataSaving::Never;
config.enableAEC = !Platform::IsMac10_7OrGreater(); config.enableAEC = !Platform::IsMac10_7OrGreater();
config.enableNS = true; config.enableNS = true;
config.enableAGC = true; config.enableAGC = true;
config.enableVolumeControl = true; config.enableVolumeControl = true;
config.initTimeout = Global::CallConnectTimeoutMs() / 1000; config.initializationTimeout = Global::CallConnectTimeoutMs() / 1000.;
config.recvTimeout = Global::CallPacketTimeoutMs() / 1000; config.receiveTimeout = Global::CallPacketTimeoutMs() / 1000.;
config.enableP2P = call.is_p2p_allowed();
config.maxApiLayer = protocol.vmax_layer().v;
if (Logs::DebugEnabled()) { if (Logs::DebugEnabled()) {
auto callLogFolder = cWorkingDir() + qsl("DebugLogs"); auto callLogFolder = cWorkingDir() + qsl("DebugLogs");
auto callLogPath = callLogFolder + qsl("/last_call_log.txt"); auto callLogPath = callLogFolder + qsl("/last_call_log.txt");
auto callLogNative = QDir::toNativeSeparators(callLogPath); auto callLogNative = QDir::toNativeSeparators(callLogPath);
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
config.logFilePath = callLogNative.toStdWString(); config.logPath = callLogNative.toStdWString();
#else // Q_OS_WIN #else // Q_OS_WIN
const auto callLogUtf = QFile::encodeName(callLogNative); const auto callLogUtf = QFile::encodeName(callLogNative);
config.logFilePath.resize(callLogUtf.size()); config.logPath.resize(callLogUtf.size());
ranges::copy(callLogUtf, config.logFilePath.begin()); ranges::copy(callLogUtf, config.logPath.begin());
#endif // Q_OS_WIN #endif // Q_OS_WIN
QFile(callLogPath).remove(); QFile(callLogPath).remove();
QDir().mkpath(callLogFolder); QDir().mkpath(callLogFolder);
} }
const auto &protocol = call.vprotocol().c_phoneCallProtocol(); auto endpoints = std::vector<TgVoipEndpoint>();
auto endpoints = std::vector<tgvoip::Endpoint>();
for (const auto &connection : call.vconnections().v) { for (const auto &connection : call.vconnections().v) {
AppendEndpoint(endpoints, connection); AppendEndpoint(endpoints, connection);
} }
auto callbacks = tgvoip::VoIPController::Callbacks(); auto proxy = TgVoipProxy();
callbacks.connectionStateChanged = [](
tgvoip::VoIPController *controller,
int state) {
const auto call = static_cast<Call*>(controller->implData);
call->handleControllerStateChange(controller, state);
};
callbacks.signalBarCountChanged = [](
tgvoip::VoIPController *controller,
int count) {
const auto call = static_cast<Call*>(controller->implData);
call->handleControllerBarCountChange(controller, count);
};
_controller.create();
if (_mute) {
_controller->SetMicMute(_mute);
}
_controller->implData = static_cast<void*>(this);
_controller->SetRemoteEndpoints(
endpoints,
call.is_p2p_allowed(),
protocol.vmax_layer().v);
_controller->SetConfig(config);
_controller->SetCurrentAudioOutput(Global::CallOutputDeviceID().toStdString());
_controller->SetCurrentAudioInput(Global::CallInputDeviceID().toStdString());
_controller->SetOutputVolume(Global::CallOutputVolume()/100.0f);
_controller->SetInputVolume(Global::CallInputVolume()/100.0f);
#ifdef Q_OS_MAC
_controller->SetAudioOutputDuckingEnabled(Global::CallAudioDuckingEnabled());
#endif
_controller->SetEncryptionKey(reinterpret_cast<char*>(_authKey.data()), (_type == Type::Outgoing));
_controller->SetCallbacks(callbacks);
if (Global::UseProxyForCalls() if (Global::UseProxyForCalls()
&& (Global::ProxySettings() == MTP::ProxyData::Settings::Enabled)) { && (Global::ProxySettings() == MTP::ProxyData::Settings::Enabled)) {
const auto &proxy = Global::SelectedProxy(); const auto &selected = Global::SelectedProxy();
if (proxy.supportsCalls()) { if (selected.supportsCalls()) {
Assert(proxy.type == MTP::ProxyData::Type::Socks5); Assert(selected.type == MTP::ProxyData::Type::Socks5);
_controller->SetProxy( proxy.host = selected.host.toStdString();
tgvoip::PROXY_SOCKS5, proxy.port = selected.port;
proxy.host.toStdString(), proxy.login = selected.user.toStdString();
proxy.port, proxy.password = selected.password.toStdString();
proxy.user.toStdString(),
proxy.password.toStdString());
} }
} }
_controller->Start();
_controller->Connect(); auto encryptionKey = TgVoipEncryptionKey();
encryptionKey.isOutgoing = (_type == Type::Outgoing);
encryptionKey.value = ranges::view::all(
_authKey
) | ranges::view::transform([](bytes::type byte) {
return static_cast<uint8_t>(byte);
}) | ranges::to_vector;
_controller = MakeController(
"2.4.4",
config,
TgVoipPersistentState(),
endpoints,
proxy.host.empty() ? nullptr : &proxy,
TgVoipNetworkType::Unknown,
encryptionKey);
const auto raw = _controller.get();
raw->setOnStateUpdated([=](TgVoipState state) {
handleControllerStateChange(raw, state);
});
raw->setOnSignalBarsUpdated([=](int count) {
handleControllerBarCountChange(count);
});
if (_mute) {
raw->setMuteMicrophone(_mute);
}
raw->setAudioOutputDevice(
Global::CallOutputDeviceID().toStdString());
raw->setAudioInputDevice(
Global::CallInputDeviceID().toStdString());
raw->setOutputVolume(Global::CallOutputVolume() / 100.0f);
raw->setInputVolume(Global::CallInputVolume() / 100.0f);
raw->setAudioOutputDuckingEnabled(Global::CallAudioDuckingEnabled());
} }
void Call::handleControllerStateChange( void Call::handleControllerStateChange(
tgvoip::VoIPController *controller, not_null<Controller*> controller,
int state) { TgVoipState state) {
// NB! Can be called from an arbitrary thread! // NB! Can be called from an arbitrary thread!
// This can be called from ~VoIPController()! // This can be called from ~VoIPController()!
// Expects(controller == _controller.get());
Expects(controller->implData == static_cast<void*>(this));
switch (state) { switch (state) {
case tgvoip::STATE_WAIT_INIT: { case TgVoipState::WaitInit: {
DEBUG_LOG(("Call Info: State changed to WaitingInit.")); DEBUG_LOG(("Call Info: State changed to WaitingInit."));
setStateQueued(State::WaitingInit); setStateQueued(State::WaitingInit);
} break; } break;
case tgvoip::STATE_WAIT_INIT_ACK: { case TgVoipState::WaitInitAck: {
DEBUG_LOG(("Call Info: State changed to WaitingInitAck.")); DEBUG_LOG(("Call Info: State changed to WaitingInitAck."));
setStateQueued(State::WaitingInitAck); setStateQueued(State::WaitingInitAck);
} break; } break;
case tgvoip::STATE_ESTABLISHED: { case TgVoipState::Established: {
DEBUG_LOG(("Call Info: State changed to Established.")); DEBUG_LOG(("Call Info: State changed to Established."));
setStateQueued(State::Established); setStateQueued(State::Established);
} break; } break;
case tgvoip::STATE_FAILED: { case TgVoipState::Failed: {
auto error = controller->GetLastError(); auto error = QString::fromStdString(controller->getLastError());
LOG(("Call Info: State changed to Failed, error: %1.").arg(error)); LOG(("Call Info: State changed to Failed, error: %1.").arg(error));
setFailedQueued(error); setFailedQueued(error);
} break; } break;
default: LOG(("Call Error: Unexpected state in handleStateChange: %1").arg(state)); default: LOG(("Call Error: Unexpected state in handleStateChange: %1"
).arg(int(state)));
} }
} }
void Call::handleControllerBarCountChange( void Call::handleControllerBarCountChange(int count) {
tgvoip::VoIPController *controller,
int count) {
// NB! Can be called from an arbitrary thread! // NB! Can be called from an arbitrary thread!
// This can be called from ~VoIPController()! // This can be called from ~VoIPController()!
// Expects(controller == _controller.get());
Expects(controller->implData == static_cast<void*>(this));
crl::on_main(this, [=] { crl::on_main(this, [=] {
setSignalBarCount(count); setSignalBarCount(count);
@ -790,32 +754,30 @@ void Call::setState(State state) {
} }
} }
void Call::setCurrentAudioDevice(bool input, std::string deviceID){ void Call::setCurrentAudioDevice(bool input, std::string deviceID) {
if (_controller) { if (_controller) {
if (input) { if (input) {
_controller->SetCurrentAudioInput(deviceID); _controller->setAudioInputDevice(deviceID);
} else { } else {
_controller->SetCurrentAudioOutput(deviceID); _controller->setAudioOutputDevice(deviceID);
} }
} }
} }
void Call::setAudioVolume(bool input, float level){ void Call::setAudioVolume(bool input, float level) {
if (_controller) { if (_controller) {
if(input) { if (input) {
_controller->SetInputVolume(level); _controller->setInputVolume(level);
} else { } else {
_controller->SetOutputVolume(level); _controller->setOutputVolume(level);
} }
} }
} }
void Call::setAudioDuckingEnabled(bool enabled){ void Call::setAudioDuckingEnabled(bool enabled) {
#ifdef Q_OS_MAC
if (_controller) { if (_controller) {
_controller->SetAudioOutputDuckingEnabled(enabled); _controller->setAudioOutputDuckingEnabled(enabled);
} }
#endif
} }
void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) { void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) {
@ -844,7 +806,7 @@ void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) {
setState(hangupState); setState(hangupState);
auto duration = getDurationMs() / 1000; auto duration = getDurationMs() / 1000;
auto connectionId = _controller ? _controller->GetPreferredRelayID() : 0; auto connectionId = _controller ? _controller->getPreferredRelayId() : 0;
_finishByTimeoutTimer.call(kHangupTimeoutMs, [this, finalState] { setState(finalState); }); _finishByTimeoutTimer.call(kHangupTimeoutMs, [this, finalState] { setState(finalState); });
_api.request(MTPphone_DiscardCall( _api.request(MTPphone_DiscardCall(
MTP_flags(0), MTP_flags(0),
@ -870,7 +832,7 @@ void Call::setStateQueued(State state) {
}); });
} }
void Call::setFailedQueued(int error) { void Call::setFailedQueued(const QString &error) {
crl::on_main(this, [=] { crl::on_main(this, [=] {
handleControllerError(error); handleControllerError(error);
}); });
@ -887,13 +849,13 @@ void Call::handleRequestError(const RPCError &error) {
finish(FinishType::Failed); finish(FinishType::Failed);
} }
void Call::handleControllerError(int error) { void Call::handleControllerError(const QString &error) {
if (error == tgvoip::ERROR_INCOMPATIBLE) { if (error == u"ERROR_INCOMPATIBLE"_q) {
Ui::show(Box<InformBox>( Ui::show(Box<InformBox>(
Lang::Hard::CallErrorIncompatible().replace( Lang::Hard::CallErrorIncompatible().replace(
"{user}", "{user}",
_user->name))); _user->name)));
} else if (error == tgvoip::ERROR_AUDIO_IO) { } else if (error == u"ERROR_AUDIO_IO"_q) {
Ui::show(Box<InformBox>(tr::lng_call_error_audio_io(tr::now))); Ui::show(Box<InformBox>(tr::lng_call_error_audio_io(tr::now)));
} }
finish(FinishType::Failed); finish(FinishType::Failed);
@ -912,8 +874,8 @@ Call::~Call() {
destroyController(); destroyController();
} }
void UpdateConfig(const std::string& data) { void UpdateConfig(const std::string &data) {
tgvoip::ServerConfig::GetSharedInstance()->Update(data); TgVoip::setGlobalServerConfig(data);
} }
} // namespace Calls } // namespace Calls

View File

@ -19,12 +19,12 @@ class Track;
} // namespace Audio } // namespace Audio
} // namespace Media } // namespace Media
namespace tgvoip { enum class TgVoipState;
class VoIPController;
} // namespace tgvoip
namespace Calls { namespace Calls {
class Controller;
struct DhConfig { struct DhConfig {
int32 version = 0; int32 version = 0;
int32 g = 0; int32 g = 0;
@ -129,30 +129,13 @@ public:
~Call(); ~Call();
private: private:
class ControllerPointer {
public:
void create();
void reset();
bool empty() const;
bool operator==(std::nullptr_t) const;
explicit operator bool() const;
tgvoip::VoIPController *operator->() const;
tgvoip::VoIPController &operator*() const;
~ControllerPointer();
private:
std::unique_ptr<tgvoip::VoIPController> _data;
};
enum class FinishType { enum class FinishType {
None, None,
Ended, Ended,
Failed, Failed,
}; };
void handleRequestError(const RPCError &error); void handleRequestError(const RPCError &error);
void handleControllerError(int error); void handleControllerError(const QString &error);
void finish(FinishType type, const MTPPhoneCallDiscardReason &reason = MTP_phoneCallDiscardReasonDisconnect()); void finish(FinishType type, const MTPPhoneCallDiscardReason &reason = MTP_phoneCallDiscardReasonDisconnect());
void startOutgoing(); void startOutgoing();
void startIncoming(); void startIncoming();
@ -160,11 +143,9 @@ private:
void generateModExpFirst(bytes::const_span randomSeed); void generateModExpFirst(bytes::const_span randomSeed);
void handleControllerStateChange( void handleControllerStateChange(
tgvoip::VoIPController *controller, not_null<Controller*> controller,
int state); TgVoipState state);
void handleControllerBarCountChange( void handleControllerBarCountChange(int count);
tgvoip::VoIPController *controller,
int count);
void createAndStartController(const MTPDphoneCall &call); void createAndStartController(const MTPDphoneCall &call);
template <typename T> template <typename T>
@ -177,7 +158,7 @@ private:
void startConfirmedCall(const MTPDphoneCall &call); void startConfirmedCall(const MTPDphoneCall &call);
void setState(State state); void setState(State state);
void setStateQueued(State state); void setStateQueued(State state);
void setFailedQueued(int error); void setFailedQueued(const QString &error);
void setSignalBarCount(int count); void setSignalBarCount(int count);
void destroyController(); void destroyController();
@ -210,12 +191,12 @@ private:
uint64 _accessHash = 0; uint64 _accessHash = 0;
uint64 _keyFingerprint = 0; uint64 _keyFingerprint = 0;
ControllerPointer _controller; std::unique_ptr<Controller> _controller;
std::unique_ptr<Media::Audio::Track> _waitingTrack; std::unique_ptr<Media::Audio::Track> _waitingTrack;
}; };
void UpdateConfig(const std::string& data); void UpdateConfig(const std::string &data);
} // namespace Calls } // namespace Calls

View File

@ -0,0 +1,31 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "calls/calls_controller.h"
#include "calls/calls_controller_tgvoip.h"
namespace Calls {
[[nodiscard]] std::unique_ptr<Controller> MakeController(
const std::string &version,
const TgVoipConfig &config,
const TgVoipPersistentState &persistentState,
const std::vector<TgVoipEndpoint> &endpoints,
const TgVoipProxy *proxy,
TgVoipNetworkType initialNetworkType,
const TgVoipEncryptionKey &encryptionKey) {
return std::make_unique<TgVoipController>(
config,
persistentState,
endpoints,
proxy,
initialNetworkType,
encryptionKey);
}
} // namespace Calls

View File

@ -0,0 +1,53 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "TgVoip.h"
namespace Calls {
class Controller {
public:
virtual ~Controller() = default;
[[nodiscard]] virtual std::string version() = 0;
virtual void setNetworkType(TgVoipNetworkType networkType) = 0;
virtual void setMuteMicrophone(bool muteMicrophone) = 0;
virtual void setAudioOutputGainControlEnabled(bool enabled) = 0;
virtual void setEchoCancellationStrength(int strength) = 0;
virtual void setAudioInputDevice(std::string id) = 0;
virtual void setAudioOutputDevice(std::string id) = 0;
virtual void setInputVolume(float level) = 0;
virtual void setOutputVolume(float level) = 0;
virtual void setAudioOutputDuckingEnabled(bool enabled) = 0;
virtual std::string getLastError() = 0;
virtual std::string getDebugInfo() = 0;
virtual int64_t getPreferredRelayId() = 0;
virtual TgVoipTrafficStats getTrafficStats() = 0;
virtual TgVoipPersistentState getPersistentState() = 0;
virtual void setOnStateUpdated(Fn<void(TgVoipState)> onStateUpdated) = 0;
virtual void setOnSignalBarsUpdated(
Fn<void(int)> onSignalBarsUpdated) = 0;
virtual TgVoipFinalState stop() = 0;
};
[[nodiscard]] std::unique_ptr<Controller> MakeController(
const std::string &version,
const TgVoipConfig &config,
const TgVoipPersistentState &persistentState,
const std::vector<TgVoipEndpoint> &endpoints,
const TgVoipProxy *proxy,
TgVoipNetworkType initialNetworkType,
const TgVoipEncryptionKey &encryptionKey);
} // namespace Calls

View File

@ -0,0 +1,97 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "calls/calls_controller.h"
namespace Calls {
class TgVoipController final : public Controller {
public:
TgVoipController(
const TgVoipConfig &config,
const TgVoipPersistentState &persistentState,
const std::vector<TgVoipEndpoint> &endpoints,
const TgVoipProxy *proxy,
TgVoipNetworkType initialNetworkType,
const TgVoipEncryptionKey &encryptionKey)
: _impl(TgVoip::makeInstance(
config,
persistentState,
endpoints,
proxy,
initialNetworkType,
encryptionKey)) {
}
[[nodiscard]] static std::string Version() {
return TgVoip::getVersion();
}
[[nodiscard]] std::string version() override {
return Version();
}
void setNetworkType(TgVoipNetworkType networkType) override {
_impl->setNetworkType(networkType);
}
void setMuteMicrophone(bool muteMicrophone) override {
_impl->setMuteMicrophone(muteMicrophone);
}
void setAudioOutputGainControlEnabled(bool enabled) override {
_impl->setAudioOutputGainControlEnabled(enabled);
}
void setEchoCancellationStrength(int strength) override {
_impl->setEchoCancellationStrength(strength);
}
void setAudioInputDevice(std::string id) override {
_impl->setAudioInputDevice(id);
}
void setAudioOutputDevice(std::string id) override {
_impl->setAudioOutputDevice(id);
}
void setInputVolume(float level) override {
_impl->setInputVolume(level);
}
void setOutputVolume(float level) override {
_impl->setOutputVolume(level);
}
void setAudioOutputDuckingEnabled(bool enabled) override {
_impl->setAudioOutputDuckingEnabled(enabled);
}
std::string getLastError() override {
return _impl->getLastError();
}
std::string getDebugInfo() override {
return _impl->getDebugInfo();
}
int64_t getPreferredRelayId() override {
return _impl->getPreferredRelayId();
}
TgVoipTrafficStats getTrafficStats() override {
return _impl->getTrafficStats();
}
TgVoipPersistentState getPersistentState() override {
return _impl->getPersistentState();
}
void setOnStateUpdated(Fn<void(TgVoipState)> onStateUpdated) override {
_impl->setOnStateUpdated(std::move(onStateUpdated));
}
void setOnSignalBarsUpdated(
Fn<void(int)> onSignalBarsUpdated) override {
_impl->setOnSignalBarsUpdated(std::move(onSignalBarsUpdated));
}
TgVoipFinalState stop() override {
return _impl->stop();
}
private:
const std::unique_ptr<TgVoip> _impl;
};
} // namespace Calls