/* 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 "media/streaming/media_streaming_common.h" #include "media/streaming/media_streaming_file_delegate.h" #include "base/weak_ptr.h" #include "base/timer.h" namespace Data { class Session; } // namespace Data namespace Media { namespace Player { struct TrackState; } // namespace Player } // namespace Media namespace Media { namespace Streaming { class Loader; class File; class AudioTrack; class VideoTrack; class Player final : private FileDelegate { public: // Public interfaces is used from the main thread. Player(not_null owner, std::unique_ptr loader); // Because we remember 'this' in calls to crl::on_main. Player(const Player &other) = delete; Player &operator=(const Player &other) = delete; void play(const PlaybackOptions &options); void pause(); void resume(); void stop(); bool valid() const; bool ready() const; float64 speed() const; void setSpeed(float64 speed); // 0.5 <= speed <= 2. [[nodiscard]] bool playing() const; [[nodiscard]] bool buffering() const; [[nodiscard]] bool paused() const; [[nodiscard]] bool failed() const; [[nodiscard]] bool finished() const; [[nodiscard]] rpl::producer updates() const; [[nodiscard]] QImage frame(const FrameRequest &request) const; [[nodiscard]] Media::Player::TrackState prepareLegacyState() const; [[nodiscard]] rpl::lifetime &lifetime(); ~Player(); private: enum class Stage { Uninitialized, Initializing, Ready, Started, Failed }; // Thread-safe. not_null delegate(); // FileDelegate methods are called only from the File thread. void fileReady(Stream &&video, Stream &&audio) override; void fileError() override; void fileWaitingForData() override; bool fileProcessPacket(Packet &&packet) override; bool fileReadMore() override; // Called from the main thread. void streamReady(Information &&information); void streamFailed(); void start(); void provideStartInformation(); void fail(); void checkNextFrame(); void renderFrame(crl::time now); void audioReceivedTill(crl::time position); void audioPlayedTill(crl::time position); void videoReceivedTill(crl::time position); void videoPlayedTill(crl::time position); void updatePausedState(); [[nodiscard]] bool trackReceivedEnough( const TrackState &state, crl::time amount) const; [[nodiscard]] bool bothReceivedEnough(crl::time amount) const; [[nodiscard]] bool receivedTillEnd() const; void checkResumeFromWaitingForData(); template void trackReceivedTill( const Track &track, TrackState &state, crl::time position); template void trackSendReceivedTill( const Track &track, TrackState &state); template void trackPlayedTill( const Track &track, TrackState &state, crl::time position); const std::unique_ptr _file; // Immutable while File is active after it is ready. AudioMsgId _audioId; std::unique_ptr _audio; std::unique_ptr _video; // Immutable while File is active. base::has_weak_ptr _sessionGuard; PlaybackOptions _options; // Belongs to the File thread while File is active. bool _readTillEnd = false; bool _waitingForData = false; std::atomic _pauseReading = false; // Belongs to the main thread. Information _information; Stage _stage = Stage::Uninitialized; bool _pausedByUser = false; bool _pausedByWaitingForData = false; bool _paused = false; bool _audioFinished = false; bool _videoFinished = false; crl::time _startedTime = kTimeUnknown; crl::time _pausedTime = kTimeUnknown; crl::time _nextFrameTime = kTimeUnknown; base::Timer _renderFrameTimer; rpl::event_stream _updates; rpl::lifetime _lifetime; rpl::lifetime _sessionLifetime; }; } // namespace Streaming } // namespace Media