tdesktop/Telegram/SourceFiles/media/media_audio.h

302 lines
7.4 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
2016-02-08 10:56:18 +00:00
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
2014-09-04 07:33:44 +00:00
*/
#pragma once
#include "core/basic_types.h"
2014-09-04 07:33:44 +00:00
void audioInit();
bool audioWorks();
void audioPlayNotify();
void audioFinish();
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
};
class AudioPlayerFader;
class AudioPlayerLoaders;
struct VideoSoundData;
struct VideoSoundPart;
struct AudioPlaybackState {
AudioPlayerState state = AudioPlayerStopped;
int64 position = 0;
int64 duration = 0;
int32 frequency = 0;
};
class AudioPlayer : public QObject, public base::Observable<AudioMsgId> {
2014-09-04 07:33:44 +00:00
Q_OBJECT
public:
2015-05-29 18:52:43 +00:00
AudioPlayer();
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);
int64 getVideoCorrectedTime(uint64 playId, int64 frameMs, uint64 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
2015-06-03 12:18:46 +00:00
void resumeDevice();
2014-09-04 07:33:44 +00:00
2015-05-29 18:52:43 +00:00
~AudioPlayer();
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
2015-07-03 08:47:16 +00:00
void songVolumeChanged();
void videoVolumeChanged();
2015-07-03 08:47:16 +00:00
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;
AudioMsg _audioData[AudioSimultaneousLimit];
int _songCurrent;
AudioMsg _songData[AudioSimultaneousLimit];
2014-09-04 07:33:44 +00:00
AudioMsg _videoData;
uint64 _lastVideoPlayId = 0;
uint64 _lastVideoPlaybackWhen = 0;
uint64 _lastVideoPlaybackCorrectedMs = 0;
QMutex _lastVideoMutex;
2014-09-04 07:33:44 +00:00
QMutex _mutex;
2015-05-29 18:52:43 +00:00
friend class AudioPlayerFader;
friend class AudioPlayerLoaders;
2014-09-04 07:33:44 +00:00
2015-05-29 18:52:43 +00:00
QThread _faderThread, _loaderThread;
AudioPlayerFader *_fader;
AudioPlayerLoaders *_loader;
2014-09-04 07:33:44 +00:00
};
namespace internal {
QMutex *audioPlayerMutex();
float64 audioSuppressGain();
float64 audioSuppressSongGain();
bool audioCheckError();
} // namespace internal
class AudioCaptureInner;
2015-05-29 18:52:43 +00:00
class AudioCapture : public QObject {
Q_OBJECT
public:
AudioCapture();
bool check();
2015-05-29 18:52:43 +00:00
~AudioCapture();
signals:
void start();
void stop(bool needResult);
2015-05-29 18:52:43 +00:00
void done(QByteArray data, VoiceWaveform waveform, qint32 samples);
void updated(quint16 level, qint32 samples);
void error();
2015-05-29 18:52:43 +00:00
private:
friend class AudioCaptureInner;
QThread _captureThread;
AudioCaptureInner *_capture;
};
AudioPlayer *audioPlayer();
AudioCapture *audioCapture();
class AudioPlayerFader : public QObject {
2014-09-04 07:33:44 +00:00
Q_OBJECT
public:
2015-05-29 18:52:43 +00:00
AudioPlayerFader(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(AudioPlayer::AudioMsg *m, bool &hasPlaying, bool &hasFading, float64 suppressGain, bool suppressGainChanged);
void setStoppedState(AudioPlayer::AudioMsg *m, AudioPlayerState state = AudioPlayerStopped);
2015-06-03 12:18:46 +00:00
QTimer _timer, _pauseTimer;
QMutex _pauseMutex;
bool _pauseFlag, _paused;
2014-09-04 07:33:44 +00:00
bool _suppressAll, _suppressAllAnim, _suppressSong, _suppressSongAnim, _songVolumeChanged, _videoVolumeChanged;
anim::fvalue _suppressAllGain, _suppressSongGain;
uint64 _suppressAllStart, _suppressSongStart;
2014-09-04 07:33:44 +00:00
};
struct AudioCapturePrivate;
2016-07-22 15:01:24 +00:00
struct AVFrame;
2015-05-29 18:52:43 +00:00
class AudioCaptureInner : public QObject {
Q_OBJECT
public:
AudioCaptureInner(QThread *thread);
~AudioCaptureInner();
signals:
void error();
void updated(quint16 level, qint32 samples);
void done(QByteArray data, VoiceWaveform waveform, qint32 samples);
2015-05-29 18:52:43 +00:00
public slots:
2015-05-29 18:52:43 +00:00
void onInit();
void onStart();
void onStop(bool needResult);
void onTimeout();
private:
2016-07-22 15:01:24 +00:00
void processFrame(int32 offset, int32 framesize);
void writeFrame(AVFrame *frame);
// Writes the packets till EAGAIN is got from av_receive_packet()
// Returns number of packets written or -1 on error
int writePackets();
2015-05-29 18:52:43 +00:00
AudioCapturePrivate *d;
QTimer _timer;
QByteArray _captured;
};
MTPDocumentAttribute audioReadSongAttributes(const QString &fname, const QByteArray &data, QImage &cover, QByteArray &coverBytes, QByteArray &coverFormat);
VoiceWaveform audioCountWaveform(const FileLocation &file, const QByteArray &data);