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 "ui/effects/animation_value.h"
11 #include "ui/chat/attach/attach_prepare.h"
12 #include "core/file_location.h"
13 #include "data/data_audio_msg_id.h"
14 #include "base/bytes.h"
15 #include "base/timer.h"
16 
17 #include <QtCore/QTimer>
18 
19 namespace Media {
20 struct ExternalSoundData;
21 struct ExternalSoundPart;
22 } // namespace Media
23 
24 namespace Media {
25 namespace Streaming {
26 struct TimePoint;
27 } // namespace Streaming
28 } // namespace Media
29 
30 namespace Media {
31 namespace Audio {
32 
33 class Instance;
34 
35 // Thread: Main.
36 void Start(not_null<Instance*> instance);
37 void Finish(not_null<Instance*> instance);
38 
39 // Thread: Main. Locks: AudioMutex.
40 bool IsAttachedToDevice();
41 
42 // Thread: Any. Must be locked: AudioMutex.
43 bool AttachToDevice();
44 
45 // Thread: Any.
46 void ScheduleDetachFromDeviceSafe();
47 void ScheduleDetachIfNotUsedSafe();
48 void StopDetachIfNotUsedSafe();
49 bool SupportsSpeedControl();
50 
51 } // namespace Audio
52 
53 namespace Player {
54 
55 constexpr auto kDefaultFrequency = 48000; // 48 kHz
56 constexpr auto kTogetherLimit = 4;
57 constexpr auto kWaveformSamplesCount = 100;
58 
59 class Fader;
60 class Loaders;
61 
62 base::Observable<AudioMsgId> &Updated();
63 
64 float64 ComputeVolume(AudioMsgId::Type type);
65 
66 enum class State {
67 	Stopped = 0x01,
68 	StoppedAtEnd = 0x02,
69 	StoppedAtError = 0x03,
70 	StoppedAtStart = 0x04,
71 
72 	Starting = 0x08,
73 	Playing = 0x10,
74 	Stopping = 0x18,
75 	Pausing = 0x20,
76 	Paused = 0x28,
77 	PausedAtEnd = 0x30,
78 	Resuming = 0x38,
79 };
80 
IsStopped(State state)81 inline bool IsStopped(State state) {
82 	return (state == State::Stopped)
83 		|| (state == State::StoppedAtEnd)
84 		|| (state == State::StoppedAtError)
85 		|| (state == State::StoppedAtStart);
86 }
87 
IsStoppedOrStopping(State state)88 inline bool IsStoppedOrStopping(State state) {
89 	return IsStopped(state) || (state == State::Stopping);
90 }
91 
IsStoppedAtEnd(State state)92 inline bool IsStoppedAtEnd(State state) {
93 	return (state == State::StoppedAtEnd);
94 }
95 
IsPaused(State state)96 inline bool IsPaused(State state) {
97 	return (state == State::Paused)
98 		|| (state == State::PausedAtEnd);
99 }
100 
IsPausedOrPausing(State state)101 inline bool IsPausedOrPausing(State state) {
102 	return IsPaused(state) || (state == State::Pausing);
103 }
104 
IsFading(State state)105 inline bool IsFading(State state) {
106 	return (state == State::Starting)
107 		|| (state == State::Stopping)
108 		|| (state == State::Pausing)
109 		|| (state == State::Resuming);
110 }
111 
IsActive(State state)112 inline bool IsActive(State state) {
113 	return !IsStopped(state) && !IsPaused(state);
114 }
115 
ShowPauseIcon(State state)116 inline bool ShowPauseIcon(State state) {
117 	return !IsStoppedOrStopping(state)
118 		&& !IsPausedOrPausing(state);
119 }
120 
121 struct TrackState {
122 	AudioMsgId id;
123 	State state = State::Stopped;
124 	int64 position = 0;
125 	int64 receivedTill = 0;
126 	int64 length = 0;
127 	int frequency = kDefaultFrequency;
128 	int fileHeaderSize = 0;
129 	bool waitingForData = false;
130 };
131 
132 class Mixer final : public QObject {
133 	Q_OBJECT
134 
135 public:
136 	explicit Mixer(not_null<Audio::Instance*> instance);
137 
138 	void play(
139 		const AudioMsgId &audio,
140 		std::unique_ptr<ExternalSoundData> externalData,
141 		crl::time positionMs);
142 	void pause(const AudioMsgId &audio, bool fast = false);
143 	void resume(const AudioMsgId &audio, bool fast = false);
144 	void stop(const AudioMsgId &audio);
145 	void stop(const AudioMsgId &audio, State state);
146 
147 	// External player audio stream interface.
148 	void feedFromExternal(ExternalSoundPart &&part);
149 	void forceToBufferExternal(const AudioMsgId &audioId);
150 
151 	// Thread: Main. Locks: AudioMutex.
152 	void setSpeedFromExternal(const AudioMsgId &audioId, float64 speed);
153 
154 	Streaming::TimePoint getExternalSyncTimePoint(
155 		const AudioMsgId &audio) const;
156 	crl::time getExternalCorrectedTime(
157 		const AudioMsgId &id,
158 		crl::time frameMs,
159 		crl::time systemMs);
160 
161 	void stopAndClear();
162 
163 	TrackState currentState(AudioMsgId::Type type);
164 
165 	// Thread: Main. Must be locked: AudioMutex.
166 	void prepareToCloseDevice();
167 
168 	// Thread: Main. Must be locked: AudioMutex.
169 	void reattachIfNeeded();
170 
171 	// Thread: Any. Must be locked: AudioMutex.
172 	void reattachTracks();
173 
174 	// Thread: Any.
175 	void setSongVolume(float64 volume);
176 	float64 getSongVolume() const;
177 	void setVideoVolume(float64 volume);
178 	float64 getVideoVolume() const;
179 
180 	~Mixer();
181 
182 private Q_SLOTS:
183 	void onError(const AudioMsgId &audio);
184 	void onStopped(const AudioMsgId &audio);
185 
186 	void onUpdated(const AudioMsgId &audio);
187 
188 Q_SIGNALS:
189 	void updated(const AudioMsgId &audio);
190 	void stoppedOnError(const AudioMsgId &audio);
191 	void loaderOnStart(const AudioMsgId &audio, qint64 positionMs);
192 	void loaderOnCancel(const AudioMsgId &audio);
193 
194 	void faderOnTimer();
195 
196 	void suppressSong();
197 	void unsuppressSong();
198 	void suppressAll(qint64 duration);
199 
200 private:
201 	struct SpeedEffect {
202 		uint32 effect = 0;
203 		uint32 effectSlot = 0;
204 		uint32 filter = 0;
205 		int coarseTune = 0;
206 		float64 speed = 1.;
207 	};
208 
209 	class Track {
210 	public:
211 		static constexpr int kBuffersCount = 3;
212 
213 		// Thread: Any. Must be locked: AudioMutex.
214 		void reattach(AudioMsgId::Type type);
215 
216 		// Thread: Main. Must be locked: AudioMutex.
217 		void detach();
218 		void clear();
219 
220 		void started();
221 
222 		bool isStreamCreated() const;
223 		void ensureStreamCreated(AudioMsgId::Type type);
224 
225 		int getNotQueuedBufferIndex();
226 
227 		// Thread: Main. Must be locked: AudioMutex.
228 		void setExternalData(std::unique_ptr<ExternalSoundData> data);
229 		void changeSpeedEffect(float64 speed);
230 
231 		~Track();
232 
233 		TrackState state;
234 
235 		Core::FileLocation file;
236 		QByteArray data;
237 		int64 bufferedPosition = 0;
238 		int64 bufferedLength = 0;
239 		bool loading = false;
240 		bool loaded = false;
241 		int64 fadeStartPosition = 0;
242 
243 		int32 format = 0;
244 		int32 frequency = kDefaultFrequency;
245 		int samplesCount[kBuffersCount] = { 0 };
246 		QByteArray bufferSamples[kBuffersCount];
247 
248 		struct Stream {
249 			uint32 source = 0;
250 			uint32 buffers[kBuffersCount] = { 0 };
251 		};
252 		Stream stream;
253 		std::unique_ptr<ExternalSoundData> externalData;
254 
255 		std::unique_ptr<SpeedEffect> speedEffect;
256 		crl::time lastUpdateWhen = 0;
257 		crl::time lastUpdatePosition = 0;
258 
259 	private:
260 		void createStream(AudioMsgId::Type type);
261 		void destroyStream();
262 		void resetStream();
263 		void resetSpeedEffect();
264 		void applySourceSpeedEffect();
265 		void removeSourceSpeedEffect();
266 
267 	};
268 
269 	bool fadedStop(AudioMsgId::Type type, bool *fadedStart = 0);
270 	void resetFadeStartPosition(AudioMsgId::Type type, int positionInBuffered = -1);
271 	bool checkCurrentALError(AudioMsgId::Type type);
272 
273 	void externalSoundProgress(const AudioMsgId &audio);
274 
275 	// Thread: Any. Must be locked: AudioMutex.
276 	void setStoppedState(Track *current, State state = State::Stopped);
277 
278 	Track *trackForType(AudioMsgId::Type type, int index = -1); // -1 uses currentIndex(type)
279 	const Track *trackForType(AudioMsgId::Type type, int index = -1) const;
280 	int *currentIndex(AudioMsgId::Type type);
281 	const int *currentIndex(AudioMsgId::Type type) const;
282 
283 	// Thread: Any. Must be locked: AudioMutex.
284 	void scheduleEffectDestruction(const SpeedEffect &effect);
285 	void scheduleEffectsDestruction();
286 
287 	// Thread: Main. Must be locked: AudioMutex.
288 	void destroyStaleEffects();
289 	void destroyEffectsOnClose();
290 
291 	// Thread: Main. Locks: AudioMutex.
292 	void destroyStaleEffectsSafe();
293 
294 	const not_null<Audio::Instance*> _instance;
295 
296 	int _audioCurrent = 0;
297 	Track _audioTracks[kTogetherLimit];
298 
299 	int _songCurrent = 0;
300 	Track _songTracks[kTogetherLimit];
301 
302 	Track _videoTrack;
303 
304 	std::vector<std::pair<crl::time, SpeedEffect>> _effectsForDestruction;
305 	base::Timer _effectsDestructionTimer;
306 
307 	QAtomicInt _volumeVideo;
308 	QAtomicInt _volumeSong;
309 
310 	friend class Fader;
311 	friend class Loaders;
312 
313 	QThread _faderThread, _loaderThread;
314 	Fader *_fader;
315 	Loaders *_loader;
316 
317 	rpl::lifetime _lifetime;
318 
319 };
320 
321 Mixer *mixer();
322 
323 class Fader : public QObject {
324 	Q_OBJECT
325 
326 public:
327 	Fader(QThread *thread);
328 
329 Q_SIGNALS:
330 	void error(const AudioMsgId &audio);
331 	void playPositionUpdated(const AudioMsgId &audio);
332 	void audioStopped(const AudioMsgId &audio);
333 	void needToPreload(const AudioMsgId &audio);
334 
335 public Q_SLOTS:
336 	void onInit();
337 	void onTimer();
338 
339 	void onSuppressSong();
340 	void onUnsuppressSong();
341 	void onSuppressAll(qint64 duration);
342 	void onSongVolumeChanged();
343 	void onVideoVolumeChanged();
344 
345 private:
346 	enum {
347 		EmitError = 0x01,
348 		EmitStopped = 0x02,
349 		EmitPositionUpdated = 0x04,
350 		EmitNeedToPreload = 0x08,
351 	};
352 	int32 updateOnePlayback(Mixer::Track *track, bool &hasPlaying, bool &hasFading, float64 volumeMultiplier, bool volumeChanged);
353 	void setStoppedState(Mixer::Track *track, State state = State::Stopped);
354 
355 	QTimer _timer;
356 
357 	bool _volumeChangedSong = false;
358 	bool _volumeChangedVideo = false;
359 
360 	bool _suppressAll = false;
361 	bool _suppressAllAnim = false;
362 	bool _suppressSong = false;
363 	bool _suppressSongAnim = false;
364 	anim::value _suppressVolumeAll;
365 	anim::value _suppressVolumeSong;
366 	crl::time _suppressAllStart = 0;
367 	crl::time _suppressAllEnd = 0;
368 	crl::time _suppressSongStart = 0;
369 
370 };
371 
372 [[nodiscard]] Ui::PreparedFileInformation::Song PrepareForSending(
373 	const QString &fname,
374 	const QByteArray &data);
375 
376 namespace internal {
377 
378 // Thread: Any. Must be locked: AudioMutex.
379 bool CheckAudioDeviceConnected();
380 
381 // Thread: Main. Locks: AudioMutex.
382 void DetachFromDevice(not_null<Audio::Instance*> instance);
383 
384 // Thread: Any.
385 QMutex *audioPlayerMutex();
386 
387 // Thread: Any.
388 bool audioCheckError();
389 
390 } // namespace internal
391 
392 } // namespace Player
393 } // namespace Media
394 
395 VoiceWaveform audioCountWaveform(const Core::FileLocation &file, const QByteArray &data);
396 
397 namespace Media {
398 namespace Audio {
399 
ReadOneSample(uchar data)400 TG_FORCE_INLINE uint16 ReadOneSample(uchar data) {
401 	return qAbs((static_cast<int16>(data) - 0x80) * 0x100);
402 }
403 
ReadOneSample(int16 data)404 TG_FORCE_INLINE uint16 ReadOneSample(int16 data) {
405 	return qAbs(data);
406 }
407 
408 template <typename SampleType, typename Callback>
IterateSamples(bytes::const_span bytes,Callback && callback)409 void IterateSamples(bytes::const_span bytes, Callback &&callback) {
410 	auto samplesPointer = reinterpret_cast<const SampleType*>(bytes.data());
411 	auto samplesCount = bytes.size() / sizeof(SampleType);
412 	auto samplesData = gsl::make_span(samplesPointer, samplesCount);
413 	for (auto sampleData : samplesData) {
414 		callback(ReadOneSample(sampleData));
415 	}
416 }
417 
418 } // namespace Audio
419 } // namespace Media
420