Add tgcalls library.

This commit is contained in:
John Preston 2020-07-09 21:38:26 +04:00
parent b703f4e555
commit 12e0399cf4
11 changed files with 333 additions and 107 deletions

3
.gitmodules vendored
View File

@ -97,3 +97,6 @@
[submodule "Telegram/lib_webrtc"]
path = Telegram/lib_webrtc
url = https://github.com/desktop-app/lib_webrtc.git
[submodule "Telegram/ThirdParty/tgcalls"]
path = Telegram/ThirdParty/tgcalls
url = https://github.com/TelegramMessenger/tgcalls.git

View File

@ -35,6 +35,7 @@ include(cmake/lib_ffmpeg.cmake)
include(cmake/lib_mtproto.cmake)
include(cmake/lib_scheme.cmake)
include(cmake/lib_tgvoip.cmake)
include(cmake/lib_tgcalls.cmake)
set(style_files
boxes/boxes.style
@ -102,6 +103,8 @@ endif()
target_link_libraries(Telegram
PRIVATE
tdesktop::lib_tgcalls_legacy
tdesktop::lib_tgcalls
tdesktop::lib_tgvoip
tdesktop::lib_mtproto
tdesktop::lib_scheme
@ -315,11 +318,6 @@ PRIVATE
calls/calls_box_controller.h
calls/calls_call.cpp
calls/calls_call.h
calls/calls_controller.cpp
calls/calls_controller.h
calls/calls_controller_tgvoip.h
calls/calls_controller_webrtc.cpp
calls/calls_controller_webrtc.h
calls/calls_emoji_fingerprint.cpp
calls/calls_emoji_fingerprint.h
calls/calls_instance.cpp

View File

@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "calls/calls_call.h"
#include "main/main_session.h"
#include "main/main_account.h"
#include "main/main_app_config.h"
#include "apiwrap.h"
#include "lang/lang_keys.h"
#include "boxes/confirm_box.h"
@ -21,11 +23,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/audio/media_audio_track.h"
#include "base/platform/base_platform_info.h"
#include "calls/calls_panel.h"
#include "calls/calls_controller.h"
#include "data/data_user.h"
#include "data/data_session.h"
#include "facades.h"
#include "tgcalls/Instance.h"
namespace tgcalls {
class InstanceImpl;
class InstanceImplLegacy;
void SetLegacyGlobalServerConfig(const std::string &serverConfig);
} // namespace tgcalls
namespace Calls {
namespace {
@ -34,20 +43,23 @@ constexpr auto kHangupTimeoutMs = 5000;
constexpr auto kSha256Size = 32;
const auto kDefaultVersion = "2.4.4"_q;
const auto RegisterTag = tgcalls::Register<tgcalls::InstanceImpl>();
const auto RegisterTagLegacy = tgcalls::Register<tgcalls::InstanceImplLegacy>();
void AppendEndpoint(
std::vector<TgVoipEndpoint> &list,
std::vector<tgcalls::Endpoint> &list,
const MTPPhoneConnection &connection) {
connection.match([&](const MTPDphoneConnection &data) {
if (data.vpeer_tag().v.length() != 16) {
return;
}
auto endpoint = TgVoipEndpoint{
auto endpoint = tgcalls::Endpoint{
.endpointId = (int64_t)data.vid().v,
.host = TgVoipEdpointHost{
.host = tgcalls::EndpointHost{
.ipv4 = data.vip().v.toStdString(),
.ipv6 = data.vipv6().v.toStdString() },
.port = (uint16_t)data.vport().v,
.type = TgVoipEndpointType::UdpRelay
.type = tgcalls::EndpointType::UdpRelay
};
const auto tag = data.vpeer_tag().v;
if (tag.size() >= 16) {
@ -83,7 +95,48 @@ uint64 ComputeFingerprint(bytes::const_span authKey) {
}
[[nodiscard]] QVector<MTPstring> CollectVersionsForApi() {
return WrapVersions(CollectControllerVersions());
return WrapVersions(tgcalls::Meta::Versions() | ranges::action::reverse);
}
[[nodiscard]] std::vector<tgcalls::RtcServer> CollectRtcServers(
not_null<UserData*> user) {
using tgcalls::RtcServer;
using List = std::vector<std::map<QString, QString>>;
auto result = std::vector<RtcServer>();
const auto list = user->account().appConfig().get<List>(
"rtc_servers",
List());
result.reserve(list.size() * 2);
for (const auto &entry : list) {
const auto find = [&](const QString &key) {
const auto i = entry.find(key);
return (i != entry.end()) ? i->second : QString();
};
const auto host = find(u"host"_q).toStdString();
const auto port = find(u"port"_q).toUShort();
const auto username = find(u"username"_q).toStdString();
const auto password = find(u"password"_q).toStdString();
if (host.empty() || !port) {
continue;
}
result.push_back(RtcServer{
.host = host,
.port = port,
.isTurn = false
});
if (username.empty() || password.empty()) {
continue;
}
result.push_back(RtcServer{
.host = host,
.port = port,
.login = username,
.password = password,
.isTurn = true,
});
}
return result;
}
} // namespace
@ -165,7 +218,7 @@ void Call::startOutgoing() {
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
MTP_int(kMinLayer),
MTP_int(ControllerMaxLayer()),
MTP_int(tgcalls::Meta::MaxLayer()),
MTP_vector(CollectVersionsForApi()))
)).done([=](const MTPphone_PhoneCall &result) {
Expects(result.type() == mtpc_phone_phoneCall);
@ -246,7 +299,7 @@ void Call::actuallyAnswer() {
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
MTP_int(kMinLayer),
MTP_int(ControllerMaxLayer()),
MTP_int(tgcalls::Meta::MaxLayer()),
MTP_vector(CollectVersionsForApi()))
)).done([=](const MTPphone_PhoneCall &result) {
Expects(result.type() == mtpc_phone_phoneCall);
@ -267,8 +320,8 @@ void Call::actuallyAnswer() {
void Call::setMute(bool mute) {
_mute = mute;
if (_controller) {
_controller->setMuteMicrophone(_mute);
if (_instance) {
_instance->setMuteMicrophone(_mute);
}
_muteChanged.notify(_mute);
}
@ -294,7 +347,7 @@ void Call::redial() {
if (_state.current() != State::Busy) {
return;
}
Assert(_controller == nullptr);
Assert(_instance == nullptr);
_type = Type::Outgoing;
setState(State::Requesting);
_answerAfterDhConfigReceived = false;
@ -303,7 +356,7 @@ void Call::redial() {
}
QString Call::getDebugLog() const {
return QString::fromStdString(_controller->getDebugInfo());
return QString::fromStdString(_instance->getDebugInfo());
}
void Call::startWaitingTrack() {
@ -418,7 +471,7 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
}
if (_type == Type::Incoming
&& _state.current() == State::ExchangingKeys
&& !_controller) {
&& !_instance) {
startConfirmedCall(data);
}
} return true;
@ -429,8 +482,8 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
return false;
}
if (data.is_need_debug()) {
auto debugLog = _controller
? _controller->getDebugInfo()
auto debugLog = _instance
? _instance->getDebugInfo()
: std::string();
if (!debugLog.empty()) {
user()->session().api().request(MTPphone_SaveCallDebug(
@ -478,17 +531,23 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
bool Call::handleSignalingData(
const MTPDupdatePhoneCallSignalingData &data) {
if (data.vphone_call_id().v != _id || !_controller) {
if (data.vphone_call_id().v != _id || !_instance) {
return false;
}
return _controller->receiveSignalingData(data.vdata().v);
auto prepared = ranges::view::all(
data.vdata().v
) | ranges::view::transform([](char byte) {
return static_cast<uint8_t>(byte);
}) | ranges::to_vector;
_instance->receiveSignalingData(std::move(prepared));
return true;
}
void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) {
Expects(_type == Type::Outgoing);
if (_state.current() == State::ExchangingKeys
|| _controller) {
|| _instance) {
LOG(("Call Warning: Unexpected confirmAcceptedCall."));
return;
}
@ -516,7 +575,7 @@ void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) {
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
MTP_int(kMinLayer),
MTP_int(ControllerMaxLayer()),
MTP_int(tgcalls::Meta::MaxLayer()),
MTP_vector(CollectVersionsForApi()))
)).done([=](const MTPphone_PhoneCall &result) {
Expects(result.type() == mtpc_phone_phoneCall);
@ -568,52 +627,80 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
const auto &protocol = call.vprotocol().c_phoneCallProtocol();
const auto &serverConfig = _user->session().serverConfig();
TgVoipConfig config;
config.dataSaving = TgVoipDataSaving::Never;
config.enableAEC = !Platform::IsMac10_7OrGreater();
config.enableNS = true;
config.enableAGC = true;
config.enableVolumeControl = true;
config.initializationTimeout = serverConfig.callConnectTimeoutMs / 1000.;
config.receiveTimeout = serverConfig.callPacketTimeoutMs / 1000.;
config.enableP2P = call.is_p2p_allowed();
config.maxApiLayer = protocol.vmax_layer().v;
const auto weak = base::make_weak(this);
auto descriptor = tgcalls::Descriptor{
.config = tgcalls::Config{
.initializationTimeout = serverConfig.callConnectTimeoutMs / 1000.,
.receiveTimeout = serverConfig.callPacketTimeoutMs / 1000.,
.dataSaving = tgcalls::DataSaving::Never,
.enableP2P = call.is_p2p_allowed(),
.enableAEC = !Platform::IsMac10_7OrGreater(),
.enableNS = true,
.enableAGC = true,
.enableVolumeControl = true,
.maxApiLayer = protocol.vmax_layer().v,
},
.videoCapture = nullptr,
.stateUpdated = [=](tgcalls::State state) {
crl::on_main(weak, [=] {
handleControllerStateChange(state);
});
},
.videoStateUpdated = [=](bool state) {
},
.signalBarsUpdated = [=](int count) {
crl::on_main(weak, [=] {
handleControllerBarCountChange(count);
});
},
.remoteVideoIsActiveUpdated = [=](bool active) {
},
.signalingDataEmitted = [=](const std::vector<uint8_t> &data) {
const auto bytes = QByteArray(
reinterpret_cast<const char*>(data.data()),
data.size());
crl::on_main(weak, [=] {
sendSignalingData(bytes);
});
},
};
if (Logs::DebugEnabled()) {
auto callLogFolder = cWorkingDir() + qsl("DebugLogs");
auto callLogPath = callLogFolder + qsl("/last_call_log.txt");
auto callLogNative = QDir::toNativeSeparators(callLogPath);
#ifdef Q_OS_WIN
config.logPath = callLogNative.toStdWString();
descriptor.config.logPath = callLogNative.toStdWString();
#else // Q_OS_WIN
const auto callLogUtf = QFile::encodeName(callLogNative);
config.logPath.resize(callLogUtf.size());
descriptor.config.logPath.resize(callLogUtf.size());
ranges::copy(callLogUtf, config.logPath.begin());
#endif // Q_OS_WIN
QFile(callLogPath).remove();
QDir().mkpath(callLogFolder);
}
auto endpoints = std::vector<TgVoipEndpoint>();
for (const auto &connection : call.vconnections().v) {
AppendEndpoint(endpoints, connection);
AppendEndpoint(descriptor.endpoints, connection);
}
auto proxy = TgVoipProxy();
descriptor.rtcServers = CollectRtcServers(_user);
if (Global::UseProxyForCalls()
&& (Global::ProxySettings() == MTP::ProxyData::Settings::Enabled)) {
const auto &selected = Global::SelectedProxy();
if (selected.supportsCalls()) {
if (selected.supportsCalls() && !selected.host.isEmpty()) {
Assert(selected.type == MTP::ProxyData::Type::Socks5);
proxy.host = selected.host.toStdString();
proxy.port = selected.port;
proxy.login = selected.user.toStdString();
proxy.password = selected.password.toStdString();
descriptor.proxy = std::make_unique<tgcalls::Proxy>();
descriptor.proxy->host = selected.host.toStdString();
descriptor.proxy->port = selected.port;
descriptor.proxy->login = selected.user.toStdString();
descriptor.proxy->password = selected.password.toStdString();
}
}
auto encryptionKey = TgVoipEncryptionKey();
encryptionKey.isOutgoing = (_type == Type::Outgoing);
encryptionKey.value = ranges::view::all(
descriptor.encryptionKey.isOutgoing = (_type == Type::Outgoing);
descriptor.encryptionKey.value = ranges::view::all(
_authKey
) | ranges::view::transform([](bytes::type byte) {
return static_cast<uint8_t>(byte);
@ -623,28 +710,26 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
const MTPDphoneCallProtocol &data) {
return data.vlibrary_versions().v;
}).value(0, MTP_bytes(kDefaultVersion)).v;
_controller = MakeController(
version.toStdString(),
config,
TgVoipPersistentState(),
endpoints,
proxy.host.empty() ? nullptr : &proxy,
TgVoipNetworkType::Unknown,
encryptionKey,
[=](QByteArray data) { sendSignalingData(data); },
[=](QImage frame) { displayNextFrame(frame); });
const auto raw = _controller.get();
raw->setOnStateUpdated([=](TgVoipState state) {
handleControllerStateChange(raw, state);
});
raw->setOnSignalBarsUpdated([=](int count) {
handleControllerBarCountChange(count);
});
LOG(("Call Info: Creating instance with version '%1', allowP2P: %2"
).arg(QString::fromUtf8(version)
).arg(Logs::b(descriptor.config.enableP2P)));
_instance = tgcalls::Meta::Create(
version.toStdString(),
std::move(descriptor));
if (!_instance) {
LOG(("Call Error: Wrong library version: %1."
).arg(QString::fromUtf8(version)));
finish(FinishType::Failed);
return;
}
const auto raw = _instance.get();
if (_mute) {
raw->setMuteMicrophone(_mute);
}
const auto &settings = Core::App().settings();
//raw->setIncomingVideoOutput(std::make_shared<rtc::VideoSinkInterface<webrtc::VideoFrame>>())
raw->setAudioOutputDevice(
settings.callOutputDeviceID().toStdString());
raw->setAudioInputDevice(
@ -654,32 +739,27 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
raw->setAudioOutputDuckingEnabled(settings.callAudioDuckingEnabled());
}
void Call::handleControllerStateChange(
not_null<Controller*> controller,
TgVoipState state) {
// NB! Can be called from an arbitrary thread!
// This can be called from ~VoIPController()!
void Call::handleControllerStateChange(tgcalls::State state) {
switch (state) {
case TgVoipState::WaitInit: {
case tgcalls::State::WaitInit: {
DEBUG_LOG(("Call Info: State changed to WaitingInit."));
setStateQueued(State::WaitingInit);
setState(State::WaitingInit);
} break;
case TgVoipState::WaitInitAck: {
case tgcalls::State::WaitInitAck: {
DEBUG_LOG(("Call Info: State changed to WaitingInitAck."));
setStateQueued(State::WaitingInitAck);
setState(State::WaitingInitAck);
} break;
case TgVoipState::Established: {
case tgcalls::State::Established: {
DEBUG_LOG(("Call Info: State changed to Established."));
setStateQueued(State::Established);
setState(State::Established);
} break;
case TgVoipState::Failed: {
auto error = QString::fromStdString(controller->getLastError());
case tgcalls::State::Failed: {
auto error = QString::fromStdString(_instance->getLastError());
LOG(("Call Info: State changed to Failed, error: %1.").arg(error));
setFailedQueued(error);
handleControllerError(error);
} break;
default: LOG(("Call Error: Unexpected state in handleStateChange: %1"
@ -688,12 +768,7 @@ void Call::handleControllerStateChange(
}
void Call::handleControllerBarCountChange(int count) {
// NB! Can be called from an arbitrary thread!
// This can be called from ~VoIPController()!
crl::on_main(this, [=] {
setSignalBarCount(count);
});
setSignalBarCount(count);
}
void Call::setSignalBarCount(int count) {
@ -794,28 +869,28 @@ void Call::setState(State state) {
}
void Call::setCurrentAudioDevice(bool input, std::string deviceID) {
if (_controller) {
if (_instance) {
if (input) {
_controller->setAudioInputDevice(deviceID);
_instance->setAudioInputDevice(deviceID);
} else {
_controller->setAudioOutputDevice(deviceID);
_instance->setAudioOutputDevice(deviceID);
}
}
}
void Call::setAudioVolume(bool input, float level) {
if (_controller) {
if (_instance) {
if (input) {
_controller->setInputVolume(level);
_instance->setInputVolume(level);
} else {
_controller->setOutputVolume(level);
_instance->setOutputVolume(level);
}
}
}
void Call::setAudioDuckingEnabled(bool enabled) {
if (_controller) {
_controller->setAudioOutputDuckingEnabled(enabled);
if (_instance) {
_instance->setAudioOutputDuckingEnabled(enabled);
}
}
@ -846,7 +921,7 @@ void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) {
setState(hangupState);
auto duration = getDurationMs() / 1000;
auto connectionId = _controller ? _controller->getPreferredRelayId() : 0;
auto connectionId = _instance ? _instance->getPreferredRelayId() : 0;
_finishByTimeoutTimer.call(kHangupTimeoutMs, [this, finalState] { setState(finalState); });
_api.request(MTPphone_DiscardCall(
MTP_flags(0),
@ -902,9 +977,13 @@ void Call::handleControllerError(const QString &error) {
}
void Call::destroyController() {
if (_controller) {
if (_instance) {
AssertIsDebug();
const auto state = _instance->stop();
LOG(("CALL_LOG: %1").arg(QString::fromStdString(state.debugLog)));
DEBUG_LOG(("Call Info: Destroying call controller.."));
_controller.reset();
_instance.reset();
DEBUG_LOG(("Call Info: Call controller destroyed."));
}
setSignalBarCount(kSignalBarFinished);
@ -915,7 +994,7 @@ Call::~Call() {
}
void UpdateConfig(const std::string &data) {
TgVoip::setGlobalServerConfig(data);
tgcalls::SetLegacyGlobalServerConfig(data);
}
} // namespace Calls

View File

@ -19,12 +19,13 @@ class Track;
} // namespace Audio
} // namespace Media
enum class TgVoipState;
namespace tgcalls {
class Instance;
enum class State;
} // namespace tgcalls
namespace Calls {
class Controller;
struct DhConfig {
int32 version = 0;
int32 g = 0;
@ -153,9 +154,7 @@ private:
void displayNextFrame(QImage frame);
void generateModExpFirst(bytes::const_span randomSeed);
void handleControllerStateChange(
not_null<Controller*> controller,
TgVoipState state);
void handleControllerStateChange(tgcalls::State state);
void handleControllerBarCountChange(int count);
void createAndStartController(const MTPDphoneCall &call);
@ -202,7 +201,7 @@ private:
uint64 _accessHash = 0;
uint64 _keyFingerprint = 0;
std::unique_ptr<Controller> _controller;
std::unique_ptr<tgcalls::Instance> _instance;
std::unique_ptr<Media::Audio::Track> _waitingTrack;

View File

@ -117,6 +117,7 @@ std::vector<QString> AppConfig::getStringArray(
return getValue(key, [&](const MTPJSONValue &value) {
return value.match([&](const MTPDjsonArray &data) {
auto result = std::vector<QString>();
result.reserve(data.vvalue().v.size());
for (const auto &entry : data.vvalue().v) {
if (entry.type() != mtpc_jsonString) {
return std::move(fallback);
@ -130,6 +131,36 @@ std::vector<QString> AppConfig::getStringArray(
});
}
std::vector<std::map<QString, QString>> AppConfig::getStringMapArray(
const QString &key,
std::vector<std::map<QString, QString>> &&fallback) const {
return getValue(key, [&](const MTPJSONValue &value) {
return value.match([&](const MTPDjsonArray &data) {
auto result = std::vector<std::map<QString, QString>>();
result.reserve(data.vvalue().v.size());
for (const auto &entry : data.vvalue().v) {
if (entry.type() != mtpc_jsonObject) {
return std::move(fallback);
}
auto element = std::map<QString, QString>();
for (const auto &field : entry.c_jsonObject().vvalue().v) {
const auto &data = field.c_jsonObjectValue();
if (data.vvalue().type() != mtpc_jsonString) {
return std::move(fallback);
}
element.emplace(
qs(data.vkey()),
qs(data.vvalue().c_jsonString().vvalue()));
}
result.push_back(std::move(element));
}
return result;
}, [&](const auto &data) {
return std::move(fallback);
});
});
}
bool AppConfig::suggestionCurrent(const QString &key) const {
return !_dismissedSuggestions.contains(key)
&& ranges::contains(

View File

@ -25,6 +25,8 @@ public:
return getString(key, fallback);
} else if constexpr (std::is_same_v<Type, std::vector<QString>>) {
return getStringArray(key, std::move(fallback));
} else if constexpr (std::is_same_v<Type, std::vector<std::map<QString, QString>>>) {
return getStringMapArray(key, std::move(fallback));
} else if constexpr (std::is_same_v<Type, bool>) {
return getBool(key, fallback);
}
@ -60,6 +62,9 @@ private:
[[nodiscard]] std::vector<QString> getStringArray(
const QString &key,
std::vector<QString> &&fallback) const;
[[nodiscard]] std::vector<std::map<QString, QString>> getStringMapArray(
const QString &key,
std::vector<std::map<QString, QString>> &&fallback) const;
const not_null<Account*> _account;
std::optional<MTP::Sender> _api;

1
Telegram/ThirdParty/tgcalls vendored Submodule

@ -0,0 +1 @@
Subproject commit ccba258805478783804cf273ff8c5edffd9f009a

View File

@ -0,0 +1,102 @@
# 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
add_library(lib_tgcalls STATIC)
init_target(lib_tgcalls)
add_library(tdesktop::lib_tgcalls ALIAS lib_tgcalls)
set(tgcalls_dir ${third_party_loc}/tgcalls)
set(tgcalls_loc ${tgcalls_dir}/tgcalls)
nice_target_sources(lib_tgcalls ${tgcalls_loc}
PRIVATE
Manager.cpp
Manager.h
MediaManager.cpp
MediaManager.h
NetworkManager.cpp
NetworkManager.h
Instance.cpp
Instance.h
InstanceImpl.cpp
InstanceImpl.h
ThreadLocalObject.h
VideoCaptureInterface.cpp
VideoCaptureInterface.h
VideoCaptureInterfaceImpl.cpp
VideoCaptureInterfaceImpl.h
VideoCapturerInterface.h
platform/PlatformInterface.h
# Windows
platform/windows/WindowsInterface.cpp
platform/windows/WindowsInterface.h
platform/windows/VideoCapturerInterfaceImpl.cpp
platform/windows/VideoCapturerInterfaceImpl.h
# iOS / macOS
platform/darwin/DarwinInterface.h
platform/darwin/DarwinInterface.mm
platform/darwin/TGRTCDefaultVideoDecoderFactory.h
platform/darwin/TGRTCDefaultVideoDecoderFactory.mm
platform/darwin/TGRTCDefaultVideoEncoderFactory.h
platform/darwin/TGRTCDefaultVideoEncoderFactory.mm
platform/darwin/TGRTCVideoDecoderH265.h
platform/darwin/TGRTCVideoDecoderH265.mm
platform/darwin/TGRTCVideoEncoderH265.h
platform/darwin/TGRTCVideoEncoderH265.mm
platform/darwin/VideoCameraCapturer.h
platform/darwin/VideoCameraCapturer.mm
platform/darwin/VideoCapturerInterfaceImpl.h
platform/darwin/VideoCapturerInterfaceImpl.mm
platform/darwin/VideoMetalView.h
platform/darwin/VideoMetalView.mm
# Linux
# POSIX
)
if (WIN32)
target_compile_definitions(lib_tgcalls
PRIVATE
TARGET_OS_WIN
)
endif()
target_include_directories(lib_tgcalls
PUBLIC
${tgcalls_dir}
PRIVATE
${tgcalls_loc}
)
target_link_libraries(lib_tgcalls
PRIVATE
desktop-app::external_webrtc
)
add_library(lib_tgcalls_legacy STATIC)
init_target(lib_tgcalls_legacy)
add_library(tdesktop::lib_tgcalls_legacy ALIAS lib_tgcalls_legacy)
nice_target_sources(lib_tgcalls_legacy ${tgcalls_loc}
PRIVATE
legacy/InstanceImplLegacy.cpp
legacy/InstanceImplLegacy.h
)
target_include_directories(lib_tgcalls_legacy
PRIVATE
${tgcalls_loc}
)
target_link_libraries(lib_tgcalls_legacy
PRIVATE
tdesktop::lib_tgcalls
tdesktop::lib_tgvoip
desktop-app::external_openssl
)

View File

@ -48,8 +48,6 @@ else()
OpusEncoder.cpp
OpusEncoder.h
threading.h
TgVoip.cpp
TgVoip.h
VoIPController.cpp
VoIPGroupController.cpp
VoIPController.h

@ -1 +1 @@
Subproject commit eb5be18405d47a226f6a197280176f82b3e903bd
Subproject commit d3d96130ba245e985c79c9040459b548416efdf8

View File

@ -163,6 +163,16 @@ Open **x86 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
jom -j4 install
cd ..
mkdir webrtc
cd webrtc
copy ..\patches\webrtc.gclient .gclient
git clone https://github.com/open-webrtc-toolkit/owt-deps-webrtc src
gclient sync
cd src
..\..\..\tdesktop\Telegram\lib_webrtc\gn_build_webrtc.bat
ninja -C out/Debug webrtc test:platform_video_capturer test:video_test_common
cd ..
## Build the project
Go to ***BuildPath*\\tdesktop\\Telegram** and run (using [your **api_id** and **api_hash**](#obtain-your-api-credentials))