mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Add test implementation of webrtc calls.
This commit is contained in:
parent
438a560a79
commit
6d36176a8d
15 changed files with 367 additions and 27 deletions
|
@ -318,6 +318,8 @@ PRIVATE
|
||||||
calls/calls_controller.cpp
|
calls/calls_controller.cpp
|
||||||
calls/calls_controller.h
|
calls/calls_controller.h
|
||||||
calls/calls_controller_tgvoip.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.cpp
|
||||||
calls/calls_emoji_fingerprint.h
|
calls/calls_emoji_fingerprint.h
|
||||||
calls/calls_instance.cpp
|
calls/calls_instance.cpp
|
||||||
|
|
|
@ -13,6 +13,8 @@ pacman --noconfirm -S pkg-config
|
||||||
PKG_CONFIG_PATH="/mingw64/lib/pkgconfig:$PKG_CONFIG_PATH"
|
PKG_CONFIG_PATH="/mingw64/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||||
|
|
||||||
./configure --toolchain=msvc \
|
./configure --toolchain=msvc \
|
||||||
|
--extra-cflags="-DCONFIG_SAFE_BITSTREAM_READER=1" \
|
||||||
|
--extra-cxxflags="-DCONFIG_SAFE_BITSTREAM_READER=1" \
|
||||||
--extra-ldflags="-libpath:$FullExecPath/../opus/win32/VS2015/Win32/Release" \
|
--extra-ldflags="-libpath:$FullExecPath/../opus/win32/VS2015/Win32/Release" \
|
||||||
--disable-programs \
|
--disable-programs \
|
||||||
--disable-doc \
|
--disable-doc \
|
||||||
|
|
|
@ -1726,8 +1726,9 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||||
auto &d = update.c_updateEncryptedMessagesRead();
|
auto &d = update.c_updateEncryptedMessagesRead();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case mtpc_updatePhoneCall: {
|
case mtpc_updatePhoneCall:
|
||||||
Core::App().calls().handleUpdate(&session(), update.c_updatePhoneCall());
|
case mtpc_updatePhoneCallSignalingData: {
|
||||||
|
Core::App().calls().handleUpdate(&session(), update);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case mtpc_updateUserBlocked: {
|
case mtpc_updateUserBlocked: {
|
||||||
|
|
|
@ -32,6 +32,7 @@ namespace {
|
||||||
constexpr auto kMinLayer = 65;
|
constexpr auto kMinLayer = 65;
|
||||||
constexpr auto kHangupTimeoutMs = 5000;
|
constexpr auto kHangupTimeoutMs = 5000;
|
||||||
constexpr auto kSha256Size = 32;
|
constexpr auto kSha256Size = 32;
|
||||||
|
const auto kDefaultVersion = "2.4.4"_q;
|
||||||
|
|
||||||
void AppendEndpoint(
|
void AppendEndpoint(
|
||||||
std::vector<TgVoipEndpoint> &list,
|
std::vector<TgVoipEndpoint> &list,
|
||||||
|
@ -71,10 +72,6 @@ uint64 ComputeFingerprint(bytes::const_span authKey) {
|
||||||
| (gsl::to_integer<uint64>(hash[12]));
|
| (gsl::to_integer<uint64>(hash[12]));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::vector<std::string> CollectVersions() {
|
|
||||||
return { TgVoip::getVersion() };
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] QVector<MTPstring> WrapVersions(
|
[[nodiscard]] QVector<MTPstring> WrapVersions(
|
||||||
const std::vector<std::string> &data) {
|
const std::vector<std::string> &data) {
|
||||||
auto result = QVector<MTPstring>();
|
auto result = QVector<MTPstring>();
|
||||||
|
@ -86,13 +83,11 @@ uint64 ComputeFingerprint(bytes::const_span authKey) {
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] QVector<MTPstring> CollectVersionsForApi() {
|
[[nodiscard]] QVector<MTPstring> CollectVersionsForApi() {
|
||||||
return WrapVersions(CollectVersions());
|
return WrapVersions(CollectControllerVersions());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Call::Delegate::~Delegate() = default;
|
|
||||||
|
|
||||||
Call::Call(
|
Call::Call(
|
||||||
not_null<Delegate*> delegate,
|
not_null<Delegate*> delegate,
|
||||||
not_null<UserData*> user,
|
not_null<UserData*> user,
|
||||||
|
@ -170,7 +165,7 @@ 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::getConnectionMaxLayer()),
|
MTP_int(ControllerMaxLayer()),
|
||||||
MTP_vector(CollectVersionsForApi()))
|
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);
|
||||||
|
@ -251,7 +246,7 @@ 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::getConnectionMaxLayer()),
|
MTP_int(ControllerMaxLayer()),
|
||||||
MTP_vector(CollectVersionsForApi()))
|
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);
|
||||||
|
@ -322,6 +317,25 @@ void Call::startWaitingTrack() {
|
||||||
_waitingTrack->playInLoop();
|
_waitingTrack->playInLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Call::sendSignalingData(const QByteArray &data) {
|
||||||
|
_api.request(MTPphone_SendSignalingData(
|
||||||
|
MTP_inputPhoneCall(
|
||||||
|
MTP_long(_id),
|
||||||
|
MTP_long(_accessHash)),
|
||||||
|
MTP_bytes(data)
|
||||||
|
)).done([=](const MTPBool &result) {
|
||||||
|
if (!mtpIsTrue(result)) {
|
||||||
|
finish(FinishType::Failed);
|
||||||
|
}
|
||||||
|
}).fail([=](const RPCError &error) {
|
||||||
|
handleRequestError(error);
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Call::displayNextFrame(QImage frame) {
|
||||||
|
_frames.fire(std::move(frame));
|
||||||
|
}
|
||||||
|
|
||||||
float64 Call::getWaitingSoundPeakValue() const {
|
float64 Call::getWaitingSoundPeakValue() const {
|
||||||
if (_waitingTrack) {
|
if (_waitingTrack) {
|
||||||
auto when = crl::now() + kSoundSampleMs / 4;
|
auto when = crl::now() + kSoundSampleMs / 4;
|
||||||
|
@ -462,6 +476,14 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
||||||
Unexpected("phoneCall type inside an existing call handleUpdate()");
|
Unexpected("phoneCall type inside an existing call handleUpdate()");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Call::handleSignalingData(
|
||||||
|
const MTPDupdatePhoneCallSignalingData &data) {
|
||||||
|
if (data.vphone_call_id().v != _id || !_controller) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return _controller->receiveSignalingData(data.vdata().v);
|
||||||
|
}
|
||||||
|
|
||||||
void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) {
|
void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) {
|
||||||
Expects(_type == Type::Outgoing);
|
Expects(_type == Type::Outgoing);
|
||||||
|
|
||||||
|
@ -494,9 +516,9 @@ 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::getConnectionMaxLayer()),
|
MTP_int(ControllerMaxLayer()),
|
||||||
MTP_vector(CollectVersionsForApi()))
|
MTP_vector(CollectVersionsForApi()))
|
||||||
)).done([this](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();
|
||||||
|
@ -508,7 +530,7 @@ void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) {
|
||||||
}
|
}
|
||||||
|
|
||||||
createAndStartController(call.vphone_call().c_phoneCall());
|
createAndStartController(call.vphone_call().c_phoneCall());
|
||||||
}).fail([this](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
handleRequestError(error);
|
handleRequestError(error);
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
@ -597,14 +619,20 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
|
||||||
return static_cast<uint8_t>(byte);
|
return static_cast<uint8_t>(byte);
|
||||||
}) | ranges::to_vector;
|
}) | ranges::to_vector;
|
||||||
|
|
||||||
|
const auto version = call.vprotocol().match([&](
|
||||||
|
const MTPDphoneCallProtocol &data) {
|
||||||
|
return data.vlibrary_versions().v;
|
||||||
|
}).value(0, MTP_bytes(kDefaultVersion)).v;
|
||||||
_controller = MakeController(
|
_controller = MakeController(
|
||||||
"2.4.4",
|
version.toStdString(),
|
||||||
config,
|
config,
|
||||||
TgVoipPersistentState(),
|
TgVoipPersistentState(),
|
||||||
endpoints,
|
endpoints,
|
||||||
proxy.host.empty() ? nullptr : &proxy,
|
proxy.host.empty() ? nullptr : &proxy,
|
||||||
TgVoipNetworkType::Unknown,
|
TgVoipNetworkType::Unknown,
|
||||||
encryptionKey);
|
encryptionKey,
|
||||||
|
[=](QByteArray data) { sendSignalingData(data); },
|
||||||
|
[=](QImage frame) { displayNextFrame(frame); });
|
||||||
|
|
||||||
const auto raw = _controller.get();
|
const auto raw = _controller.get();
|
||||||
raw->setOnStateUpdated([=](TgVoipState state) {
|
raw->setOnStateUpdated([=](TgVoipState state) {
|
||||||
|
|
|
@ -48,7 +48,7 @@ public:
|
||||||
virtual void playSound(Sound sound) = 0;
|
virtual void playSound(Sound sound) = 0;
|
||||||
virtual void requestMicrophonePermissionOrFail(Fn<void()> result) = 0;
|
virtual void requestMicrophonePermissionOrFail(Fn<void()> result) = 0;
|
||||||
|
|
||||||
virtual ~Delegate();
|
virtual ~Delegate() = default;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ public:
|
||||||
|
|
||||||
void start(bytes::const_span random);
|
void start(bytes::const_span random);
|
||||||
bool handleUpdate(const MTPPhoneCall &call);
|
bool handleUpdate(const MTPPhoneCall &call);
|
||||||
|
bool handleSignalingData(const MTPDupdatePhoneCallSignalingData &data);
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
Starting,
|
Starting,
|
||||||
|
@ -110,6 +111,10 @@ public:
|
||||||
return _muteChanged;
|
return _muteChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<QImage> frames() const {
|
||||||
|
return _frames.events();
|
||||||
|
}
|
||||||
|
|
||||||
crl::time getDurationMs() const;
|
crl::time getDurationMs() const;
|
||||||
float64 getWaitingSoundPeakValue() const;
|
float64 getWaitingSoundPeakValue() const;
|
||||||
|
|
||||||
|
@ -144,6 +149,8 @@ private:
|
||||||
void startOutgoing();
|
void startOutgoing();
|
||||||
void startIncoming();
|
void startIncoming();
|
||||||
void startWaitingTrack();
|
void startWaitingTrack();
|
||||||
|
void sendSignalingData(const QByteArray &data);
|
||||||
|
void displayNextFrame(QImage frame);
|
||||||
|
|
||||||
void generateModExpFirst(bytes::const_span randomSeed);
|
void generateModExpFirst(bytes::const_span randomSeed);
|
||||||
void handleControllerStateChange(
|
void handleControllerStateChange(
|
||||||
|
@ -181,6 +188,7 @@ private:
|
||||||
|
|
||||||
bool _mute = false;
|
bool _mute = false;
|
||||||
base::Observable<bool> _muteChanged;
|
base::Observable<bool> _muteChanged;
|
||||||
|
rpl::event_stream<QImage> _frames;
|
||||||
|
|
||||||
DhConfig _dhConfig;
|
DhConfig _dhConfig;
|
||||||
bytes::vector _ga;
|
bytes::vector _ga;
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "calls/calls_controller.h"
|
#include "calls/calls_controller.h"
|
||||||
|
|
||||||
#include "calls/calls_controller_tgvoip.h"
|
#include "calls/calls_controller_tgvoip.h"
|
||||||
|
#include "calls/calls_controller_webrtc.h"
|
||||||
|
|
||||||
namespace Calls {
|
namespace Calls {
|
||||||
|
|
||||||
|
@ -18,7 +19,20 @@ namespace Calls {
|
||||||
const std::vector<TgVoipEndpoint> &endpoints,
|
const std::vector<TgVoipEndpoint> &endpoints,
|
||||||
const TgVoipProxy *proxy,
|
const TgVoipProxy *proxy,
|
||||||
TgVoipNetworkType initialNetworkType,
|
TgVoipNetworkType initialNetworkType,
|
||||||
const TgVoipEncryptionKey &encryptionKey) {
|
const TgVoipEncryptionKey &encryptionKey,
|
||||||
|
Fn<void(QByteArray)> sendSignalingData,
|
||||||
|
Fn<void(QImage)> displayNextFrame) {
|
||||||
|
if (version == WebrtcController::Version()) {
|
||||||
|
return std::make_unique<WebrtcController>(
|
||||||
|
config,
|
||||||
|
persistentState,
|
||||||
|
endpoints,
|
||||||
|
proxy,
|
||||||
|
initialNetworkType,
|
||||||
|
encryptionKey,
|
||||||
|
std::move(sendSignalingData),
|
||||||
|
std::move(displayNextFrame));
|
||||||
|
}
|
||||||
return std::make_unique<TgVoipController>(
|
return std::make_unique<TgVoipController>(
|
||||||
config,
|
config,
|
||||||
persistentState,
|
persistentState,
|
||||||
|
@ -28,4 +42,12 @@ namespace Calls {
|
||||||
encryptionKey);
|
encryptionKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> CollectControllerVersions() {
|
||||||
|
return { WebrtcController::Version(), TgVoipController::Version() };
|
||||||
|
}
|
||||||
|
|
||||||
|
int ControllerMaxLayer() {
|
||||||
|
return TgVoip::getConnectionMaxLayer();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Calls
|
} // namespace Calls
|
||||||
|
|
|
@ -26,6 +26,7 @@ public:
|
||||||
virtual void setInputVolume(float level) = 0;
|
virtual void setInputVolume(float level) = 0;
|
||||||
virtual void setOutputVolume(float level) = 0;
|
virtual void setOutputVolume(float level) = 0;
|
||||||
virtual void setAudioOutputDuckingEnabled(bool enabled) = 0;
|
virtual void setAudioOutputDuckingEnabled(bool enabled) = 0;
|
||||||
|
virtual bool receiveSignalingData(const QByteArray &data) = 0;
|
||||||
|
|
||||||
virtual std::string getLastError() = 0;
|
virtual std::string getLastError() = 0;
|
||||||
virtual std::string getDebugInfo() = 0;
|
virtual std::string getDebugInfo() = 0;
|
||||||
|
@ -48,6 +49,11 @@ public:
|
||||||
const std::vector<TgVoipEndpoint> &endpoints,
|
const std::vector<TgVoipEndpoint> &endpoints,
|
||||||
const TgVoipProxy *proxy,
|
const TgVoipProxy *proxy,
|
||||||
TgVoipNetworkType initialNetworkType,
|
TgVoipNetworkType initialNetworkType,
|
||||||
const TgVoipEncryptionKey &encryptionKey);
|
const TgVoipEncryptionKey &encryptionKey,
|
||||||
|
Fn<void(QByteArray)> sendSignalingData,
|
||||||
|
Fn<void(QImage)> displayNextFrame);
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<std::string> CollectControllerVersions();
|
||||||
|
[[nodiscard]] int ControllerMaxLayer();
|
||||||
|
|
||||||
} // namespace Calls
|
} // namespace Calls
|
||||||
|
|
|
@ -33,7 +33,7 @@ public:
|
||||||
return TgVoip::getVersion();
|
return TgVoip::getVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::string version() override {
|
std::string version() override {
|
||||||
return Version();
|
return Version();
|
||||||
}
|
}
|
||||||
void setNetworkType(TgVoipNetworkType networkType) override {
|
void setNetworkType(TgVoipNetworkType networkType) override {
|
||||||
|
@ -63,6 +63,9 @@ public:
|
||||||
void setAudioOutputDuckingEnabled(bool enabled) override {
|
void setAudioOutputDuckingEnabled(bool enabled) override {
|
||||||
_impl->setAudioOutputDuckingEnabled(enabled);
|
_impl->setAudioOutputDuckingEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
bool receiveSignalingData(const QByteArray &data) override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
std::string getLastError() override {
|
std::string getLastError() override {
|
||||||
return _impl->getLastError();
|
return _impl->getLastError();
|
||||||
}
|
}
|
||||||
|
@ -81,8 +84,7 @@ public:
|
||||||
void setOnStateUpdated(Fn<void(TgVoipState)> onStateUpdated) override {
|
void setOnStateUpdated(Fn<void(TgVoipState)> onStateUpdated) override {
|
||||||
_impl->setOnStateUpdated(std::move(onStateUpdated));
|
_impl->setOnStateUpdated(std::move(onStateUpdated));
|
||||||
}
|
}
|
||||||
void setOnSignalBarsUpdated(
|
void setOnSignalBarsUpdated(Fn<void(int)> onSignalBarsUpdated) override {
|
||||||
Fn<void(int)> onSignalBarsUpdated) override {
|
|
||||||
_impl->setOnSignalBarsUpdated(std::move(onSignalBarsUpdated));
|
_impl->setOnSignalBarsUpdated(std::move(onSignalBarsUpdated));
|
||||||
}
|
}
|
||||||
TgVoipFinalState stop() override {
|
TgVoipFinalState stop() override {
|
||||||
|
|
175
Telegram/SourceFiles/calls/calls_controller_webrtc.cpp
Normal file
175
Telegram/SourceFiles/calls/calls_controller_webrtc.cpp
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
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_webrtc.h"
|
||||||
|
|
||||||
|
#include "webrtc/webrtc_call_context.h"
|
||||||
|
|
||||||
|
namespace Calls {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace Webrtc;
|
||||||
|
|
||||||
|
[[nodiscard]] CallConnectionDescription ConvertEndpoint(const TgVoipEndpoint &data) {
|
||||||
|
return CallConnectionDescription{
|
||||||
|
.ip = QString::fromStdString(data.host.ipv4),
|
||||||
|
.ipv6 = QString::fromStdString(data.host.ipv6),
|
||||||
|
.peerTag = QByteArray(
|
||||||
|
reinterpret_cast<const char*>(data.peerTag),
|
||||||
|
base::array_size(data.peerTag)),
|
||||||
|
.connectionId = data.endpointId,
|
||||||
|
.port = data.port,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] CallContext::Config MakeContextConfig(
|
||||||
|
const TgVoipConfig &config,
|
||||||
|
const TgVoipPersistentState &persistentState,
|
||||||
|
const std::vector<TgVoipEndpoint> &endpoints,
|
||||||
|
const TgVoipProxy *proxy,
|
||||||
|
TgVoipNetworkType initialNetworkType,
|
||||||
|
const TgVoipEncryptionKey &encryptionKey,
|
||||||
|
Fn<void(QByteArray)> sendSignalingData,
|
||||||
|
Fn<void(QImage)> displayNextFrame) {
|
||||||
|
Expects(!endpoints.empty());
|
||||||
|
|
||||||
|
auto result = CallContext::Config{
|
||||||
|
.proxy = (proxy
|
||||||
|
? ProxyServer{
|
||||||
|
.host = QString::fromStdString(proxy->host),
|
||||||
|
.username = QString::fromStdString(proxy->login),
|
||||||
|
.password = QString::fromStdString(proxy->password),
|
||||||
|
.port = proxy->port }
|
||||||
|
: ProxyServer()),
|
||||||
|
.dataSaving = (config.dataSaving != TgVoipDataSaving::Never),
|
||||||
|
.key = QByteArray(
|
||||||
|
reinterpret_cast<const char*>(encryptionKey.value.data()),
|
||||||
|
encryptionKey.value.size()),
|
||||||
|
.outgoing = encryptionKey.isOutgoing,
|
||||||
|
.primary = ConvertEndpoint(endpoints.front()),
|
||||||
|
.alternatives = endpoints | ranges::view::drop(
|
||||||
|
1
|
||||||
|
) | ranges::view::transform(ConvertEndpoint) | ranges::to_vector,
|
||||||
|
.maxLayer = config.maxApiLayer,
|
||||||
|
.allowP2P = config.enableP2P,
|
||||||
|
.sendSignalingData = std::move(sendSignalingData),
|
||||||
|
.displayNextFrame = std::move(displayNextFrame),
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
WebrtcController::WebrtcController(
|
||||||
|
const TgVoipConfig &config,
|
||||||
|
const TgVoipPersistentState &persistentState,
|
||||||
|
const std::vector<TgVoipEndpoint> &endpoints,
|
||||||
|
const TgVoipProxy *proxy,
|
||||||
|
TgVoipNetworkType initialNetworkType,
|
||||||
|
const TgVoipEncryptionKey &encryptionKey,
|
||||||
|
Fn<void(QByteArray)> sendSignalingData,
|
||||||
|
Fn<void(QImage)> displayNextFrame)
|
||||||
|
: _impl(std::make_unique<CallContext>(MakeContextConfig(
|
||||||
|
config,
|
||||||
|
persistentState,
|
||||||
|
endpoints,
|
||||||
|
proxy,
|
||||||
|
initialNetworkType,
|
||||||
|
encryptionKey,
|
||||||
|
std::move(sendSignalingData),
|
||||||
|
std::move(displayNextFrame)))) {
|
||||||
|
}
|
||||||
|
|
||||||
|
WebrtcController::~WebrtcController() = default;
|
||||||
|
|
||||||
|
std::string WebrtcController::Version() {
|
||||||
|
return CallContext::Version().toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string WebrtcController::version() {
|
||||||
|
return Version();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebrtcController::setNetworkType(TgVoipNetworkType networkType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebrtcController::setMuteMicrophone(bool muteMicrophone) {
|
||||||
|
_impl->setIsMuted(muteMicrophone);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebrtcController::setAudioOutputGainControlEnabled(bool enabled) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebrtcController::setEchoCancellationStrength(int strength) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebrtcController::setAudioInputDevice(std::string id) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebrtcController::setAudioOutputDevice(std::string id) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebrtcController::setInputVolume(float level) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebrtcController::setOutputVolume(float level) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebrtcController::setAudioOutputDuckingEnabled(bool enabled) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebrtcController::receiveSignalingData(const QByteArray &data) {
|
||||||
|
return _impl->receiveSignalingData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string WebrtcController::getLastError() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string WebrtcController::getDebugInfo() {
|
||||||
|
return _impl->getDebugInfo().toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t WebrtcController::getPreferredRelayId() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TgVoipTrafficStats WebrtcController::getTrafficStats() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
TgVoipPersistentState WebrtcController::getPersistentState() {
|
||||||
|
return TgVoipPersistentState{};
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebrtcController::setOnStateUpdated(
|
||||||
|
Fn<void(TgVoipState)> onStateUpdated) {
|
||||||
|
_stateUpdatedLifetime.destroy();
|
||||||
|
_impl->state().changes(
|
||||||
|
) | rpl::start_with_next([=](CallState state) {
|
||||||
|
onStateUpdated([&] {
|
||||||
|
switch (state) {
|
||||||
|
case CallState::Initializing: return TgVoipState::WaitInit;
|
||||||
|
case CallState::Reconnecting: return TgVoipState::Reconnecting;
|
||||||
|
case CallState::Connected: return TgVoipState::Established;
|
||||||
|
case CallState::Failed: return TgVoipState::Failed;
|
||||||
|
}
|
||||||
|
Unexpected("State value in Webrtc::CallContext::state.");
|
||||||
|
}());
|
||||||
|
}, _stateUpdatedLifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebrtcController::setOnSignalBarsUpdated(
|
||||||
|
Fn<void(int)> onSignalBarsUpdated) {
|
||||||
|
}
|
||||||
|
|
||||||
|
TgVoipFinalState WebrtcController::stop() {
|
||||||
|
_impl->stop();
|
||||||
|
return TgVoipFinalState();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Calls
|
60
Telegram/SourceFiles/calls/calls_controller_webrtc.h
Normal file
60
Telegram/SourceFiles/calls/calls_controller_webrtc.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
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 Webrtc {
|
||||||
|
class CallContext;
|
||||||
|
} // namespace Webrtc
|
||||||
|
|
||||||
|
namespace Calls {
|
||||||
|
|
||||||
|
class WebrtcController final : public Controller {
|
||||||
|
public:
|
||||||
|
WebrtcController(
|
||||||
|
const TgVoipConfig &config,
|
||||||
|
const TgVoipPersistentState &persistentState,
|
||||||
|
const std::vector<TgVoipEndpoint> &endpoints,
|
||||||
|
const TgVoipProxy *proxy,
|
||||||
|
TgVoipNetworkType initialNetworkType,
|
||||||
|
const TgVoipEncryptionKey &encryptionKey,
|
||||||
|
Fn<void(QByteArray)> sendSignalingData,
|
||||||
|
Fn<void(QImage)> displayNextFrame);
|
||||||
|
~WebrtcController();
|
||||||
|
|
||||||
|
[[nodiscard]] static std::string Version();
|
||||||
|
|
||||||
|
std::string version() override;
|
||||||
|
void setNetworkType(TgVoipNetworkType networkType) override;
|
||||||
|
void setMuteMicrophone(bool muteMicrophone) override;
|
||||||
|
void setAudioOutputGainControlEnabled(bool enabled) override;
|
||||||
|
void setEchoCancellationStrength(int strength) override;
|
||||||
|
void setAudioInputDevice(std::string id) override;
|
||||||
|
void setAudioOutputDevice(std::string id) override;
|
||||||
|
void setInputVolume(float level) override;
|
||||||
|
void setOutputVolume(float level) override;
|
||||||
|
void setAudioOutputDuckingEnabled(bool enabled) override;
|
||||||
|
bool receiveSignalingData(const QByteArray &data) override;
|
||||||
|
std::string getLastError() override;
|
||||||
|
std::string getDebugInfo() override;
|
||||||
|
int64_t getPreferredRelayId() override;
|
||||||
|
TgVoipTrafficStats getTrafficStats() override;
|
||||||
|
TgVoipPersistentState getPersistentState() override;
|
||||||
|
void setOnStateUpdated(Fn<void(TgVoipState)> onStateUpdated) override;
|
||||||
|
void setOnSignalBarsUpdated(Fn<void(int)> onSignalBarsUpdated) override;
|
||||||
|
TgVoipFinalState stop() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::unique_ptr<Webrtc::CallContext> _impl;
|
||||||
|
|
||||||
|
rpl::lifetime _stateUpdatedLifetime;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Calls
|
|
@ -232,13 +232,19 @@ void Instance::refreshServerConfig(not_null<Main::Session*> session) {
|
||||||
UpdateConfig(std::string(json.data(), json.size()));
|
UpdateConfig(std::string(json.data(), json.size()));
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
_serverConfigRequestSession = nullptr;
|
_serverConfigRequestSession = nullptr;
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::handleUpdate(
|
void Instance::handleUpdate(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
const MTPDupdatePhoneCall& update) {
|
const MTPUpdate &update) {
|
||||||
handleCallUpdate(session, update.vphone_call());
|
update.match([&](const MTPDupdatePhoneCall &data) {
|
||||||
|
handleCallUpdate(session, data.vphone_call());
|
||||||
|
}, [&](const MTPDupdatePhoneCallSignalingData &data) {
|
||||||
|
handleSignalingData(data);
|
||||||
|
}, [](const auto &) {
|
||||||
|
Unexpected("Update type in Calls::Instance::handleUpdate.");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::showInfoPanel(not_null<Call*> call) {
|
void Instance::showInfoPanel(not_null<Call*> call) {
|
||||||
|
@ -291,6 +297,14 @@ void Instance::handleCallUpdate(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Instance::handleSignalingData(
|
||||||
|
const MTPDupdatePhoneCallSignalingData &data) {
|
||||||
|
if (!_currentCall || !_currentCall->handleSignalingData(data)) {
|
||||||
|
DEBUG_LOG(("API Warning: unexpected call signaling data %1"
|
||||||
|
).arg(data.vphone_call_id().v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Instance::alreadyInCall() {
|
bool Instance::alreadyInCall() {
|
||||||
return (_currentCall && _currentCall->state() != Call::State::Busy);
|
return (_currentCall && _currentCall->state() != Call::State::Busy);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ public:
|
||||||
void startOutgoingCall(not_null<UserData*> user);
|
void startOutgoingCall(not_null<UserData*> user);
|
||||||
void handleUpdate(
|
void handleUpdate(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
const MTPDupdatePhoneCall &update);
|
const MTPUpdate &update);
|
||||||
void showInfoPanel(not_null<Call*> call);
|
void showInfoPanel(not_null<Call*> call);
|
||||||
[[nodiscard]] Call *currentCall() const;
|
[[nodiscard]] Call *currentCall() const;
|
||||||
[[nodiscard]] rpl::producer<Call*> currentCallValue() const;
|
[[nodiscard]] rpl::producer<Call*> currentCallValue() const;
|
||||||
|
@ -59,6 +59,8 @@ private:
|
||||||
void destroyCurrentPanel();
|
void destroyCurrentPanel();
|
||||||
void requestMicrophonePermissionOrFail(Fn<void()> onSuccess) override;
|
void requestMicrophonePermissionOrFail(Fn<void()> onSuccess) override;
|
||||||
|
|
||||||
|
void handleSignalingData(const MTPDupdatePhoneCallSignalingData &data);
|
||||||
|
|
||||||
void refreshDhConfig();
|
void refreshDhConfig();
|
||||||
void refreshServerConfig(not_null<Main::Session*> session);
|
void refreshServerConfig(not_null<Main::Session*> session);
|
||||||
bytes::const_span updateDhConfig(const MTPmessages_DhConfig &data);
|
bytes::const_span updateDhConfig(const MTPmessages_DhConfig &data);
|
||||||
|
|
|
@ -400,6 +400,11 @@ void Panel::initControls() {
|
||||||
|
|
||||||
_decline->finishAnimating();
|
_decline->finishAnimating();
|
||||||
_cancel->finishAnimating();
|
_cancel->finishAnimating();
|
||||||
|
|
||||||
|
_call->frames() | rpl::start_with_next([=](QImage frame) {
|
||||||
|
_videoFrame = std::move(frame);
|
||||||
|
update();
|
||||||
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::reinitControls() {
|
void Panel::reinitControls() {
|
||||||
|
@ -742,6 +747,17 @@ void Panel::paintEvent(QPaintEvent *e) {
|
||||||
p.fillRect(0, _contentTop, width(), height() - _contentTop, brush);
|
p.fillRect(0, _contentTop, width(), height() - _contentTop, brush);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_videoFrame.isNull()) {
|
||||||
|
const auto to = rect().marginsRemoved(_padding);
|
||||||
|
p.save();
|
||||||
|
p.setClipRect(to);
|
||||||
|
const auto big = _videoFrame.size().scaled(to.size(), Qt::KeepAspectRatioByExpanding);
|
||||||
|
const auto pos = QPoint((to.width() - big.width()) / 2, (to.height() - big.height()) / 2);
|
||||||
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
p.drawImage(QRect(pos, big), _videoFrame);
|
||||||
|
p.restore();
|
||||||
|
}
|
||||||
|
|
||||||
if (_signalBars->isDisplayed()) {
|
if (_signalBars->isDisplayed()) {
|
||||||
paintSignalBarsBg(p);
|
paintSignalBarsBg(p);
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,6 +158,8 @@ private:
|
||||||
QPixmap _bottomCache;
|
QPixmap _bottomCache;
|
||||||
QPixmap _cache;
|
QPixmap _cache;
|
||||||
|
|
||||||
|
QImage _videoFrame;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Calls
|
} // namespace Calls
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2b1cd3b5b0c909834aea00e0590435a63d318468
|
Subproject commit eb5be18405d47a226f6a197280176f82b3e903bd
|
Loading…
Add table
Reference in a new issue