mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +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.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
|
||||
|
|
|
@ -13,6 +13,8 @@ pacman --noconfirm -S pkg-config
|
|||
PKG_CONFIG_PATH="/mingw64/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
|
||||
./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" \
|
||||
--disable-programs \
|
||||
--disable-doc \
|
||||
|
|
|
@ -1726,8 +1726,9 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
|||
auto &d = update.c_updateEncryptedMessagesRead();
|
||||
} break;
|
||||
|
||||
case mtpc_updatePhoneCall: {
|
||||
Core::App().calls().handleUpdate(&session(), update.c_updatePhoneCall());
|
||||
case mtpc_updatePhoneCall:
|
||||
case mtpc_updatePhoneCallSignalingData: {
|
||||
Core::App().calls().handleUpdate(&session(), update);
|
||||
} break;
|
||||
|
||||
case mtpc_updateUserBlocked: {
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace {
|
|||
constexpr auto kMinLayer = 65;
|
||||
constexpr auto kHangupTimeoutMs = 5000;
|
||||
constexpr auto kSha256Size = 32;
|
||||
const auto kDefaultVersion = "2.4.4"_q;
|
||||
|
||||
void AppendEndpoint(
|
||||
std::vector<TgVoipEndpoint> &list,
|
||||
|
@ -71,10 +72,6 @@ uint64 ComputeFingerprint(bytes::const_span authKey) {
|
|||
| (gsl::to_integer<uint64>(hash[12]));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::string> CollectVersions() {
|
||||
return { TgVoip::getVersion() };
|
||||
}
|
||||
|
||||
[[nodiscard]] QVector<MTPstring> WrapVersions(
|
||||
const std::vector<std::string> &data) {
|
||||
auto result = QVector<MTPstring>();
|
||||
|
@ -86,13 +83,11 @@ uint64 ComputeFingerprint(bytes::const_span authKey) {
|
|||
}
|
||||
|
||||
[[nodiscard]] QVector<MTPstring> CollectVersionsForApi() {
|
||||
return WrapVersions(CollectVersions());
|
||||
return WrapVersions(CollectControllerVersions());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Call::Delegate::~Delegate() = default;
|
||||
|
||||
Call::Call(
|
||||
not_null<Delegate*> delegate,
|
||||
not_null<UserData*> user,
|
||||
|
@ -170,7 +165,7 @@ void Call::startOutgoing() {
|
|||
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
|
||||
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
|
||||
MTP_int(kMinLayer),
|
||||
MTP_int(TgVoip::getConnectionMaxLayer()),
|
||||
MTP_int(ControllerMaxLayer()),
|
||||
MTP_vector(CollectVersionsForApi()))
|
||||
)).done([=](const MTPphone_PhoneCall &result) {
|
||||
Expects(result.type() == mtpc_phone_phoneCall);
|
||||
|
@ -251,7 +246,7 @@ void Call::actuallyAnswer() {
|
|||
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
|
||||
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
|
||||
MTP_int(kMinLayer),
|
||||
MTP_int(TgVoip::getConnectionMaxLayer()),
|
||||
MTP_int(ControllerMaxLayer()),
|
||||
MTP_vector(CollectVersionsForApi()))
|
||||
)).done([=](const MTPphone_PhoneCall &result) {
|
||||
Expects(result.type() == mtpc_phone_phoneCall);
|
||||
|
@ -322,6 +317,25 @@ void Call::startWaitingTrack() {
|
|||
_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 {
|
||||
if (_waitingTrack) {
|
||||
auto when = crl::now() + kSoundSampleMs / 4;
|
||||
|
@ -462,6 +476,14 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
|||
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) {
|
||||
Expects(_type == Type::Outgoing);
|
||||
|
||||
|
@ -494,9 +516,9 @@ void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) {
|
|||
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
|
||||
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
|
||||
MTP_int(kMinLayer),
|
||||
MTP_int(TgVoip::getConnectionMaxLayer()),
|
||||
MTP_int(ControllerMaxLayer()),
|
||||
MTP_vector(CollectVersionsForApi()))
|
||||
)).done([this](const MTPphone_PhoneCall &result) {
|
||||
)).done([=](const MTPphone_PhoneCall &result) {
|
||||
Expects(result.type() == mtpc_phone_phoneCall);
|
||||
|
||||
auto &call = result.c_phone_phoneCall();
|
||||
|
@ -508,7 +530,7 @@ void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) {
|
|||
}
|
||||
|
||||
createAndStartController(call.vphone_call().c_phoneCall());
|
||||
}).fail([this](const RPCError &error) {
|
||||
}).fail([=](const RPCError &error) {
|
||||
handleRequestError(error);
|
||||
}).send();
|
||||
}
|
||||
|
@ -597,14 +619,20 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
|
|||
return static_cast<uint8_t>(byte);
|
||||
}) | 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(
|
||||
"2.4.4",
|
||||
version.toStdString(),
|
||||
config,
|
||||
TgVoipPersistentState(),
|
||||
endpoints,
|
||||
proxy.host.empty() ? nullptr : &proxy,
|
||||
TgVoipNetworkType::Unknown,
|
||||
encryptionKey);
|
||||
encryptionKey,
|
||||
[=](QByteArray data) { sendSignalingData(data); },
|
||||
[=](QImage frame) { displayNextFrame(frame); });
|
||||
|
||||
const auto raw = _controller.get();
|
||||
raw->setOnStateUpdated([=](TgVoipState state) {
|
||||
|
|
|
@ -48,7 +48,7 @@ public:
|
|||
virtual void playSound(Sound sound) = 0;
|
||||
virtual void requestMicrophonePermissionOrFail(Fn<void()> result) = 0;
|
||||
|
||||
virtual ~Delegate();
|
||||
virtual ~Delegate() = default;
|
||||
|
||||
};
|
||||
|
||||
|
@ -70,6 +70,7 @@ public:
|
|||
|
||||
void start(bytes::const_span random);
|
||||
bool handleUpdate(const MTPPhoneCall &call);
|
||||
bool handleSignalingData(const MTPDupdatePhoneCallSignalingData &data);
|
||||
|
||||
enum State {
|
||||
Starting,
|
||||
|
@ -110,6 +111,10 @@ public:
|
|||
return _muteChanged;
|
||||
}
|
||||
|
||||
rpl::producer<QImage> frames() const {
|
||||
return _frames.events();
|
||||
}
|
||||
|
||||
crl::time getDurationMs() const;
|
||||
float64 getWaitingSoundPeakValue() const;
|
||||
|
||||
|
@ -144,6 +149,8 @@ private:
|
|||
void startOutgoing();
|
||||
void startIncoming();
|
||||
void startWaitingTrack();
|
||||
void sendSignalingData(const QByteArray &data);
|
||||
void displayNextFrame(QImage frame);
|
||||
|
||||
void generateModExpFirst(bytes::const_span randomSeed);
|
||||
void handleControllerStateChange(
|
||||
|
@ -181,6 +188,7 @@ private:
|
|||
|
||||
bool _mute = false;
|
||||
base::Observable<bool> _muteChanged;
|
||||
rpl::event_stream<QImage> _frames;
|
||||
|
||||
DhConfig _dhConfig;
|
||||
bytes::vector _ga;
|
||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "calls/calls_controller.h"
|
||||
|
||||
#include "calls/calls_controller_tgvoip.h"
|
||||
#include "calls/calls_controller_webrtc.h"
|
||||
|
||||
namespace Calls {
|
||||
|
||||
|
@ -18,7 +19,20 @@ namespace Calls {
|
|||
const std::vector<TgVoipEndpoint> &endpoints,
|
||||
const TgVoipProxy *proxy,
|
||||
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>(
|
||||
config,
|
||||
persistentState,
|
||||
|
@ -28,4 +42,12 @@ namespace Calls {
|
|||
encryptionKey);
|
||||
}
|
||||
|
||||
std::vector<std::string> CollectControllerVersions() {
|
||||
return { WebrtcController::Version(), TgVoipController::Version() };
|
||||
}
|
||||
|
||||
int ControllerMaxLayer() {
|
||||
return TgVoip::getConnectionMaxLayer();
|
||||
}
|
||||
|
||||
} // namespace Calls
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
virtual void setInputVolume(float level) = 0;
|
||||
virtual void setOutputVolume(float level) = 0;
|
||||
virtual void setAudioOutputDuckingEnabled(bool enabled) = 0;
|
||||
virtual bool receiveSignalingData(const QByteArray &data) = 0;
|
||||
|
||||
virtual std::string getLastError() = 0;
|
||||
virtual std::string getDebugInfo() = 0;
|
||||
|
@ -48,6 +49,11 @@ public:
|
|||
const std::vector<TgVoipEndpoint> &endpoints,
|
||||
const TgVoipProxy *proxy,
|
||||
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
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
return TgVoip::getVersion();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string version() override {
|
||||
std::string version() override {
|
||||
return Version();
|
||||
}
|
||||
void setNetworkType(TgVoipNetworkType networkType) override {
|
||||
|
@ -63,6 +63,9 @@ public:
|
|||
void setAudioOutputDuckingEnabled(bool enabled) override {
|
||||
_impl->setAudioOutputDuckingEnabled(enabled);
|
||||
}
|
||||
bool receiveSignalingData(const QByteArray &data) override {
|
||||
return false;
|
||||
}
|
||||
std::string getLastError() override {
|
||||
return _impl->getLastError();
|
||||
}
|
||||
|
@ -81,8 +84,7 @@ public:
|
|||
void setOnStateUpdated(Fn<void(TgVoipState)> onStateUpdated) override {
|
||||
_impl->setOnStateUpdated(std::move(onStateUpdated));
|
||||
}
|
||||
void setOnSignalBarsUpdated(
|
||||
Fn<void(int)> onSignalBarsUpdated) override {
|
||||
void setOnSignalBarsUpdated(Fn<void(int)> onSignalBarsUpdated) override {
|
||||
_impl->setOnSignalBarsUpdated(std::move(onSignalBarsUpdated));
|
||||
}
|
||||
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()));
|
||||
}).fail([=](const RPCError &error) {
|
||||
_serverConfigRequestSession = nullptr;
|
||||
}).send();
|
||||
}).send();
|
||||
}
|
||||
|
||||
void Instance::handleUpdate(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPDupdatePhoneCall& update) {
|
||||
handleCallUpdate(session, update.vphone_call());
|
||||
const MTPUpdate &update) {
|
||||
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) {
|
||||
|
@ -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() {
|
||||
return (_currentCall && _currentCall->state() != Call::State::Busy);
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public:
|
|||
void startOutgoingCall(not_null<UserData*> user);
|
||||
void handleUpdate(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPDupdatePhoneCall &update);
|
||||
const MTPUpdate &update);
|
||||
void showInfoPanel(not_null<Call*> call);
|
||||
[[nodiscard]] Call *currentCall() const;
|
||||
[[nodiscard]] rpl::producer<Call*> currentCallValue() const;
|
||||
|
@ -59,6 +59,8 @@ private:
|
|||
void destroyCurrentPanel();
|
||||
void requestMicrophonePermissionOrFail(Fn<void()> onSuccess) override;
|
||||
|
||||
void handleSignalingData(const MTPDupdatePhoneCallSignalingData &data);
|
||||
|
||||
void refreshDhConfig();
|
||||
void refreshServerConfig(not_null<Main::Session*> session);
|
||||
bytes::const_span updateDhConfig(const MTPmessages_DhConfig &data);
|
||||
|
|
|
@ -400,6 +400,11 @@ void Panel::initControls() {
|
|||
|
||||
_decline->finishAnimating();
|
||||
_cancel->finishAnimating();
|
||||
|
||||
_call->frames() | rpl::start_with_next([=](QImage frame) {
|
||||
_videoFrame = std::move(frame);
|
||||
update();
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void Panel::reinitControls() {
|
||||
|
@ -742,6 +747,17 @@ void Panel::paintEvent(QPaintEvent *e) {
|
|||
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()) {
|
||||
paintSignalBarsBg(p);
|
||||
}
|
||||
|
|
|
@ -158,6 +158,8 @@ private:
|
|||
QPixmap _bottomCache;
|
||||
QPixmap _cache;
|
||||
|
||||
QImage _videoFrame;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Calls
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 2b1cd3b5b0c909834aea00e0590435a63d318468
|
||||
Subproject commit eb5be18405d47a226f6a197280176f82b3e903bd
|
Loading…
Add table
Reference in a new issue