tdesktop/Telegram/SourceFiles/media/media_audio.h

244 lines
6.2 KiB
C
Raw Normal View History

2014-09-04 07:33:44 +00:00
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
2014-09-04 07:33:44 +00:00
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
2015-10-03 13:16:42 +00:00
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
2014-09-04 07:33:44 +00:00
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
2014-09-04 07:33:44 +00:00
*/
#pragma once
2015-05-29 18:52:43 +00:00
enum AudioPlayerState {
AudioPlayerStopped = 0x01,
AudioPlayerStoppedAtEnd = 0x02,
2015-07-03 08:47:16 +00:00
AudioPlayerStoppedAtError = 0x03,
AudioPlayerStoppedAtStart = 0x04,
AudioPlayerStoppedMask = 0x07,
AudioPlayerStarting = 0x08,
AudioPlayerPlaying = 0x10,
AudioPlayerFinishing = 0x18,
AudioPlayerPausing = 0x20,
AudioPlayerPaused = 0x28,
AudioPlayerPausedAtEnd = 0x30,
AudioPlayerResuming = 0x38,
2014-09-04 07:33:44 +00:00
};
struct VideoSoundData;
struct VideoSoundPart;
struct AudioPlaybackState {
AudioPlayerState state = AudioPlayerStopped;
int64 position = 0;
2016-12-01 19:20:33 +00:00
TimeMs duration = 0;
int32 frequency = 0;
};
namespace Media {
namespace Player {
void InitAudio();
void DeInitAudio();
base::Observable<AudioMsgId> &Updated();
bool CreateAudioPlaybackDevice();
void PlayNotify();
class Fader;
class Loaders;
class Mixer : public QObject, private base::Subscriber {
2014-09-04 07:33:44 +00:00
Q_OBJECT
public:
Mixer();
2014-09-04 07:33:44 +00:00
2015-07-03 08:47:16 +00:00
void play(const AudioMsgId &audio, int64 position = 0);
void pauseresume(AudioMsgId::Type type, bool fast = false);
void seek(int64 position); // type == AudioMsgId::Type::Song
void stop(AudioMsgId::Type type);
// Video player audio stream interface.
void initFromVideo(uint64 videoPlayId, std_::unique_ptr<VideoSoundData> &&data, int64 position);
void feedFromVideo(VideoSoundPart &&part);
2016-12-01 19:20:33 +00:00
int64 getVideoCorrectedTime(uint64 playId, TimeMs frameMs, TimeMs systemMs);
AudioPlaybackState currentVideoState(uint64 videoPlayId);
void stopFromVideo(uint64 videoPlayId);
void pauseFromVideo(uint64 videoPlayId);
void resumeFromVideo(uint64 videoPlayId);
void stopAndClear();
AudioPlaybackState currentState(AudioMsgId *audio, AudioMsgId::Type type);
void clearStoppedAtStart(const AudioMsgId &audio);
2014-09-04 07:33:44 +00:00
~Mixer();
2014-09-04 07:33:44 +00:00
private slots:
void onError(const AudioMsgId &audio);
void onStopped(const AudioMsgId &audio);
2014-09-04 07:33:44 +00:00
void onUpdated(const AudioMsgId &audio);
2014-09-04 07:33:44 +00:00
signals:
void updated(const AudioMsgId &audio);
2015-07-03 08:47:16 +00:00
void stoppedOnError(const AudioMsgId &audio);
void loaderOnStart(const AudioMsgId &audio, qint64 position);
void loaderOnCancel(const AudioMsgId &audio);
2014-09-04 07:33:44 +00:00
void faderOnTimer();
2015-07-03 08:47:16 +00:00
void suppressSong();
void unsuppressSong();
void suppressAll();
2014-09-04 07:33:44 +00:00
private:
bool fadedStop(AudioMsgId::Type type, bool *fadedStart = 0);
bool updateCurrentStarted(AudioMsgId::Type type, int32 pos = -1);
bool checkCurrentALError(AudioMsgId::Type type);
void videoSoundProgress(const AudioMsgId &audio);
struct AudioMsg {
void clear();
AudioMsgId audio;
FileLocation file;
2014-09-04 07:33:44 +00:00
QByteArray data;
AudioPlaybackState playbackState = defaultState();
int64 skipStart = 0;
int64 skipEnd = 0;
bool loading = false;
int64 started = 0;
uint32 source = 0;
int32 nextBuffer = 0;
uint32 buffers[3] = { 0 };
int64 samplesCount[3] = { 0 };
uint64 videoPlayId = 0;
std_::unique_ptr<VideoSoundData> videoData;
private:
static AudioPlaybackState defaultState() {
AudioPlaybackState result;
result.frequency = AudioVoiceMsgFrequency;
return result;
}
};
void setStoppedState(AudioMsg *current, AudioPlayerState state = AudioPlayerStopped);
AudioMsg *dataForType(AudioMsgId::Type type, int index = -1); // -1 uses currentIndex(type)
const AudioMsg *dataForType(AudioMsgId::Type type, int index = -1) const;
int *currentIndex(AudioMsgId::Type type);
const int *currentIndex(AudioMsgId::Type type) const;
2014-09-04 07:33:44 +00:00
int _audioCurrent = 0;
AudioMsg _audioData[AudioSimultaneousLimit];
int _songCurrent = 0;
AudioMsg _songData[AudioSimultaneousLimit];
2014-09-04 07:33:44 +00:00
AudioMsg _videoData;
uint64 _lastVideoPlayId = 0;
2016-12-01 19:20:33 +00:00
TimeMs _lastVideoPlaybackWhen = 0;
TimeMs _lastVideoPlaybackCorrectedMs = 0;
QMutex _lastVideoMutex;
2014-09-04 07:33:44 +00:00
QMutex _mutex;
friend class Fader;
friend class Loaders;
2014-09-04 07:33:44 +00:00
2015-05-29 18:52:43 +00:00
QThread _faderThread, _loaderThread;
Fader *_fader;
Loaders *_loader;
2015-05-29 18:52:43 +00:00
};
Mixer *mixer();
2015-05-29 18:52:43 +00:00
class Fader : public QObject {
2014-09-04 07:33:44 +00:00
Q_OBJECT
public:
Fader(QThread *thread);
2015-06-03 12:18:46 +00:00
void resumeDevice();
2014-09-04 07:33:44 +00:00
signals:
void error(const AudioMsgId &audio);
void playPositionUpdated(const AudioMsgId &audio);
void audioStopped(const AudioMsgId &audio);
void needToPreload(const AudioMsgId &audio);
2014-09-04 07:33:44 +00:00
2015-06-03 12:18:46 +00:00
void stopPauseDevice();
2015-01-10 13:08:30 +00:00
public slots:
2014-09-04 07:33:44 +00:00
void onInit();
void onTimer();
2015-06-03 12:18:46 +00:00
void onPauseTimer();
void onPauseTimerStop();
2014-09-04 07:33:44 +00:00
void onSuppressSong();
void onUnsuppressSong();
void onSuppressAll();
2015-07-03 08:47:16 +00:00
void onSongVolumeChanged();
void onVideoVolumeChanged();
2014-09-04 07:33:44 +00:00
private:
enum {
EmitError = 0x01,
EmitStopped = 0x02,
EmitPositionUpdated = 0x04,
EmitNeedToPreload = 0x08,
};
int32 updateOnePlayback(Mixer::AudioMsg *m, bool &hasPlaying, bool &hasFading, float64 suppressGain, bool suppressGainChanged);
void setStoppedState(Mixer::AudioMsg *m, AudioPlayerState state = AudioPlayerStopped);
2015-06-03 12:18:46 +00:00
QTimer _timer, _pauseTimer;
QMutex _pauseMutex;
bool _pauseFlag = false;
bool _paused = true;
bool _suppressAll = false;
bool _suppressAllAnim = false;
bool _suppressSong = false;
bool _suppressSongAnim = false;
bool _songVolumeChanged, _videoVolumeChanged;
anim::value _suppressAllGain, _suppressSongGain;
2016-12-01 19:20:33 +00:00
TimeMs _suppressAllStart = 0;
TimeMs _suppressSongStart = 0;
2014-09-04 07:33:44 +00:00
};
} // namespace Player
} // namespace Media
namespace internal {
2015-05-29 18:52:43 +00:00
QMutex *audioPlayerMutex();
float64 audioSuppressGain();
float64 audioSuppressSongGain();
bool audioCheckError();
2015-05-29 18:52:43 +00:00
} // namespace internal
MTPDocumentAttribute audioReadSongAttributes(const QString &fname, const QByteArray &data, QImage &cover, QByteArray &coverBytes, QByteArray &coverFormat);
VoiceWaveform audioCountWaveform(const FileLocation &file, const QByteArray &data);