1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #pragma once
9 
10 #include "media/streaming/media_streaming_utility.h"
11 
12 namespace Media {
13 namespace Streaming {
14 
15 class AudioTrack final {
16 public:
17 	// Called from some unspecified thread.
18 	// Callbacks are assumed to be thread-safe.
19 	AudioTrack(
20 		const PlaybackOptions &options,
21 		Stream &&stream,
22 		AudioMsgId audioId,
23 		FnMut<void(const Information &)> ready,
24 		Fn<void(Error)> error);
25 
26 	// Called from the main thread.
27 	// Must be called after 'ready' was invoked.
28 	void pause(crl::time time);
29 	void resume(crl::time time);
30 
31 	// Allow to irreversibly stop only audio track.
32 	void stop();
33 
34 	// Called from the main thread.
35 	void setSpeed(float64 speed);
36 	[[nodiscard]] rpl::producer<> waitingForData() const;
37 
38 	// Called from the main thread.
39 	// Non-const, because we subscribe to changes on the first call.
40 	// Must be called after 'ready' was invoked.
41 	[[nodiscard]] rpl::producer<crl::time> playPosition();
42 
43 	// Thread-safe.
44 	[[nodiscard]] int streamIndex() const;
45 	[[nodiscard]] AVRational streamTimeBase() const;
46 	[[nodiscard]] crl::time streamDuration() const;
47 
48 	// Called from the same unspecified thread.
49 	void process(std::vector<FFmpeg::Packet> &&packets);
50 	void waitForData();
51 
52 	// Called from the main thread.
53 	~AudioTrack();
54 
55 private:
56 	// Called from the same unspecified thread.
57 	[[nodiscard]] bool initialized() const;
58 	[[nodiscard]] bool tryReadFirstFrame(FFmpeg::Packet &&packet);
59 	[[nodiscard]] bool fillStateFromFrame();
60 	[[nodiscard]] bool processFirstFrame();
61 	void mixerInit();
62 	void mixerEnqueue(gsl::span<FFmpeg::Packet> packets);
63 	void mixerForceToBuffer();
64 	void callReady();
65 
66 	PlaybackOptions _options;
67 
68 	// Accessed from the same unspecified thread.
69 	Stream _stream;
70 	const AudioMsgId _audioId;
71 	bool _readTillEnd = false;
72 
73 	// Assumed to be thread-safe.
74 	FnMut<void(const Information &)> _ready;
75 	const Fn<void(Error)> _error;
76 
77 	// First set from the same unspecified thread before _ready is called.
78 	// After that is immutable.
79 	crl::time _startedPosition = kTimeUnknown;
80 
81 	// Accessed from the main thread.
82 	base::Subscription _subscription;
83 	rpl::event_stream<> _waitingForData;
84 	// First set from the same unspecified thread before _ready is called.
85 	// After that accessed from the main thread.
86 	rpl::variable<crl::time> _playPosition;
87 
88 	// For initial frame skipping for an exact seek.
89 	FFmpeg::FramePointer _initialSkippingFrame;
90 
91 };
92 
93 } // namespace Streaming
94 } // namespace Media
95