Files
AyuGramDesktop/Telegram/SourceFiles/media/view/media_view_video_stream.cpp
T
2025-11-15 11:59:19 +04:00

233 lines
6.4 KiB
C++

/*
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 "media/view/media_view_video_stream.h"
#include "calls/group/calls_group_call.h"
#include "calls/group/calls_group_common.h"
#include "calls/group/calls_group_members.h"
#include "calls/group/calls_group_messages.h"
#include "calls/group/calls_group_messages_ui.h"
#include "calls/group/calls_group_viewport.h"
#include "calls/calls_instance.h"
#include "chat_helpers/compose/compose_show.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "styles/style_calls.h"
namespace Media::View {
class VideoStream::Delegate final : public Calls::GroupCall::Delegate {
public:
Delegate();
void groupCallFinished(not_null<Calls::GroupCall*> call) override;
void groupCallFailed(not_null<Calls::GroupCall*> call) override;
void groupCallRequestPermissionsOrFail(Fn<void()> onSuccess) override;
void groupCallPlaySound(GroupCallSound sound) override;
auto groupCallGetVideoCapture(const QString &deviceId)
-> std::shared_ptr<tgcalls::VideoCaptureInterface> override;
FnMut<void()> groupCallAddAsyncWaiter() override;
private:
};
VideoStream::Delegate::Delegate() {
}
void VideoStream::Delegate::groupCallFinished(
not_null<Calls::GroupCall*> call) {
// #TODO videostreams
}
void VideoStream::Delegate::groupCallFailed(not_null<Calls::GroupCall*> call) {
// #TODO videostreams
}
void VideoStream::Delegate::groupCallRequestPermissionsOrFail(
Fn<void()> onSuccess) {
}
void VideoStream::Delegate::groupCallPlaySound(GroupCallSound sound) {
}
auto VideoStream::Delegate::groupCallGetVideoCapture(const QString &deviceId)
-> std::shared_ptr<tgcalls::VideoCaptureInterface> {
return nullptr;
}
FnMut<void()> VideoStream::Delegate::groupCallAddAsyncWaiter() {
// #TODO videostreams
return [] {};
}
VideoStream::VideoStream(
not_null<QWidget*> parent,
not_null<Ui::RpWidgetWrap*> borrowedRp,
bool borrowedOpenGL,
Ui::GL::Backend backend,
std::shared_ptr<ChatHelpers::Show> show,
std::shared_ptr<Data::GroupCall> call,
QString callLinkSlug,
MsgId callJoinMessageId)
: _show(std::move(show))
, _delegate(std::make_unique<Delegate>())
, _call(std::make_unique<Calls::GroupCall>(
_delegate.get(),
Calls::StartConferenceInfo{
.show = _show,
.call = std::move(call),
.linkSlug = callLinkSlug,
.joinMessageId = callJoinMessageId,
}))
, _members(
std::make_unique<Calls::Group::Members>(
parent,
_call.get(),
Calls::Group::PanelMode::VideoStream,
backend))
, _viewport(
std::make_unique<Calls::Group::Viewport>(
parent,
Calls::Group::PanelMode::VideoStream,
backend,
borrowedRp,
borrowedOpenGL))
, _messages(
std::make_unique<Calls::Group::MessagesUi>(
parent,
_show,
Calls::Group::MessagesMode::VideoStream,
_call->messages()->listValue(),
_call->messages()->idUpdates(),
_call->canManageValue(),
rpl::combine(
_call->messagesEnabledValue(),
_commentsShown.value(),
rpl::mappers::_1 && rpl::mappers::_2))) {
Core::App().calls().registerVideoStream(_call.get());
setupMembers();
setupVideo();
setupMessages();
}
VideoStream::~VideoStream() {
}
not_null<Calls::GroupCall*> VideoStream::call() const {
return _call.get();
}
void VideoStream::updateGeometry(int x, int y, int width, int height) {
const auto skip = st::groupCallMessageSkip;
_viewport->setGeometry(false, { x, y, width, height });
_messages->move(x + skip, y + height, width - 2 * skip, height / 2);
}
void VideoStream::toggleCommentsOn(rpl::producer<bool> shown) {
_commentsShown = std::move(shown);
}
void VideoStream::ensureBorrowedRenderer(QOpenGLFunctions &f) {
_viewport->ensureBorrowedRenderer(f);
}
void VideoStream::ensureBorrowedCleared(QOpenGLFunctions *f) {
_viewport->ensureBorrowedCleared(f);
}
void VideoStream::borrowedPaint(QOpenGLFunctions &f) {
_viewport->borrowedPaint(f);
}
void VideoStream::borrowedPaint(Painter &p, const QRegion &clip) {
_viewport->borrowedPaint(p, clip);
}
void VideoStream::setupMembers() {
}
void VideoStream::setupVideo() {
const auto setupTile = [=](
const Calls::VideoEndpoint &endpoint,
const std::unique_ptr<Calls::GroupCall::VideoTrack> &track) {
using namespace rpl::mappers;
const auto row = endpoint.rtmp()
? _members->rtmpFakeRow(Calls::GroupCall::TrackPeer(track)).get()
: _members->lookupRow(Calls::GroupCall::TrackPeer(track));
Assert(row != nullptr);
auto pinned = rpl::combine(
_call->videoEndpointLargeValue(),
_call->videoEndpointPinnedValue()
) | rpl::map(_1 == endpoint && _2);
const auto self = (endpoint.peer == _call->joinAs());
_viewport->add(
endpoint,
Calls::Group::VideoTileTrack{
Calls::GroupCall::TrackPointer(track),
row,
},
Calls::GroupCall::TrackSizeValue(track),
std::move(pinned),
self);
};
for (const auto &[endpoint, track] : _call->activeVideoTracks()) {
setupTile(endpoint, track);
}
_call->videoStreamActiveUpdates(
) | rpl::start_with_next([=](const Calls::VideoStateToggle &update) {
if (update.value) {
// Add async (=> the participant row is definitely in Members).
const auto endpoint = update.endpoint;
crl::on_main(_viewport->widget(), [=] {
const auto &tracks = _call->activeVideoTracks();
const auto i = tracks.find(endpoint);
if (i != end(tracks)) {
setupTile(endpoint, i->second);
}
});
} else {
// Remove sync.
_viewport->remove(update.endpoint);
}
}, _viewport->lifetime());
_viewport->qualityRequests(
) | rpl::start_with_next([=](const Calls::VideoQualityRequest &request) {
_call->requestVideoQuality(request.endpoint, request.quality);
}, _viewport->lifetime());
_viewport->widget()->lower();
_viewport->setControlsShown(0.);
setVolume(Core::App().settings().videoVolume());
}
void VideoStream::setupMessages() {
_messages->hiddenShowRequested() | rpl::start_with_next([=] {
_call->messages()->requestHiddenShow();
}, _messages->lifetime());
_messages->deleteRequests(
) | rpl::start_with_next([=](Calls::Group::MessageDeleteRequest event) {
_call->messages()->deleteConfirmed(event);
}, _messages->lifetime());
}
void VideoStream::setVolume(float64 volume) {
const auto value = volume * Calls::Group::kDefaultVolume;
_call->changeVolume({
.peer = _call->peer(),
.volume = int(base::SafeRound(value)),
});
}
} // namespace Media::View