/* 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/player/media_player_round_controller.h" #include "media/audio/media_audio.h" #include "media/clip/media_clip_reader.h" #include "media/player/media_player_instance.h" #include "media/view/media_view_playback_progress.h" #include "history/history_item.h" #include "window/window_controller.h" #include "data/data_media_types.h" #include "data/data_document.h" #include "data/data_session.h" #include "auth_session.h" namespace Media { namespace Player { struct RoundController::CreateTag { }; std::unique_ptr RoundController::TryStart( not_null parent, not_null item) { const auto media = item->media(); if (!media) { return nullptr; } const auto document = media->document(); if (!document || !document->isVideoMessage()) { return nullptr; } return std::make_unique(CreateTag(), parent, item); } RoundController::RoundController( CreateTag&&, not_null parent, not_null item) : _parent(parent) , _data(item->media()->document()) , _context(item) { Expects(_data->isVideoMessage()); subscribe(instance()->updatedNotifier(), [this](const TrackState &state) { handleAudioUpdate(state); }); _reader = Clip::MakeReader( _data, _context->fullId(), [=](Clip::Notification notification) { callback(notification); }, Clip::Reader::Mode::Video); _playbackProgress = std::make_unique(); _playbackProgress->setValueChangedCallback([=](float64, float64) { Auth().data().requestItemRepaint(_context); }); Auth().data().markMediaRead(_data); Auth().data().itemRemoved( ) | rpl::start_with_next([=](not_null item) { if (item == _context) { stop(State::Stopped); } }, lifetime()); Auth().data().itemRepaintRequest( ) | rpl::start_with_next([=](not_null item) { if (item == _context) { crl::on_main(this, [=] { checkReaderState(); }); } }, lifetime()); } rpl::lifetime &RoundController::lifetime() { return _lifetime; } FullMsgId RoundController::contextId() const { return _context->fullId(); } void RoundController::pauseResume() { if (checkReaderState()) { _reader->pauseResumeVideo(); } } Clip::Reader *RoundController::reader() const { return _reader ? _reader.get() : nullptr; } View::PlaybackProgress *RoundController::playback() const { return _playbackProgress.get(); } void RoundController::handleAudioUpdate(const TrackState &state) { if (state.id.type() != AudioMsgId::Type::Voice) { return; } const auto audio = _reader->audioMsgId(); const auto another = (state.id != _reader->audioMsgId()); const auto stopped = IsStoppedOrStopping(state.state); if ((another && !stopped) || (!another && stopped)) { stop(State::Stopped); return; } else if (another) { return; } if (_playbackProgress) { _playbackProgress->updateState(state); } if (IsPaused(state.state) || state.state == State::Pausing) { if (!_reader->videoPaused()) { _reader->pauseResumeVideo(); } } else { if (_reader->videoPaused()) { _reader->pauseResumeVideo(); } } } void RoundController::callback(Clip::Notification notification) { if (!_reader) { return; } switch (notification) { case Clip::NotificationReinit: { if (checkReaderState()) { Auth().data().requestItemResize(_context); } } break; case Clip::NotificationRepaint: { Auth().data().requestItemRepaint(_context); } break; } } bool RoundController::checkReaderState() { if (!_reader) { return false; } const auto state = _reader->state(); if (state == Media::Clip::State::Error) { stop(State::StoppedAtError); return false; } else if (state == Media::Clip::State::Finished) { stop(State::StoppedAtEnd); return false; } else if (_reader->ready() && !_reader->started()) { const auto size = QSize(_reader->width(), _reader->height()) / cIntRetinaFactor(); _reader->start( size.width(), size.height(), size.width(), size.height(), ImageRoundRadius::Ellipse, RectPart::AllCorners); } return true; } void RoundController::stop(State state) { if (const auto audioId = _reader->audioMsgId()) { mixer()->stop(audioId, state); } _parent->roundVideoFinished(this); } RoundController::~RoundController() = default; } // namespace Player } // namespace Media