/* 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 "base/observer.h" #include "media/streaming/media_streaming_utility.h" namespace Media { namespace Streaming { class AudioTrack final { public: // Called from some unspecified thread. // Callbacks are assumed to be thread-safe. AudioTrack( const PlaybackOptions &options, Stream &&stream, AudioMsgId audioId, FnMut ready, Fn error); // Called from the main thread. // Must be called after 'ready' was invoked. void pause(crl::time time); void resume(crl::time time); // Allow to irreversibly stop only audio track. void stop(); // Called from the main thread. void setSpeed(float64 speed); [[nodiscard]] rpl::producer<> waitingForData() const; // Called from the main thread. // Non-const, because we subscribe to changes on the first call. // Must be called after 'ready' was invoked. [[nodiscard]] rpl::producer playPosition(); // Thread-safe. [[nodiscard]] int streamIndex() const; [[nodiscard]] AVRational streamTimeBase() const; [[nodiscard]] crl::time streamDuration() const; // Called from the same unspecified thread. void process(std::vector &&packets); void waitForData(); // Called from the main thread. ~AudioTrack(); private: // Called from the same unspecified thread. [[nodiscard]] bool initialized() const; [[nodiscard]] bool tryReadFirstFrame(FFmpeg::Packet &&packet); [[nodiscard]] bool fillStateFromFrame(); [[nodiscard]] bool processFirstFrame(); void mixerInit(); void mixerEnqueue(gsl::span packets); void mixerForceToBuffer(); void callReady(); PlaybackOptions _options; // Accessed from the same unspecified thread. Stream _stream; const AudioMsgId _audioId; bool _readTillEnd = false; // Assumed to be thread-safe. FnMut _ready; const Fn _error; // First set from the same unspecified thread before _ready is called. // After that is immutable. crl::time _startedPosition = kTimeUnknown; // Accessed from the main thread. base::Subscription _subscription; rpl::event_stream<> _waitingForData; // First set from the same unspecified thread before _ready is called. // After that accessed from the main thread. rpl::variable _playPosition; // For initial frame skipping for an exact seek. FFmpeg::FramePointer _initialSkippingFrame; }; } // namespace Streaming } // namespace Media