234 lines
8.6 KiB
C++
234 lines
8.6 KiB
C++
/******************************************************************************
|
|
QtAV: Multimedia framework based on Qt and FFmpeg
|
|
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
|
|
|
* This file is part of QtAV
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library 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
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
******************************************************************************/
|
|
|
|
#ifndef QAV_AUDIOOUTPUT_H
|
|
#define QAV_AUDIOOUTPUT_H
|
|
|
|
#include <QtCore/QObject>
|
|
#include <QtCore/QStringList>
|
|
#include "AVOutput.h"
|
|
#include "AudioFrame.h"
|
|
|
|
/*!
|
|
* AudioOutput ao;
|
|
* ao.setAudioFormat(fmt);
|
|
* ao.open();
|
|
* while (has_data) {
|
|
* data = read_data(ao->bufferSize());
|
|
* ao->play(data, pts);
|
|
* }
|
|
* ao->close();
|
|
* See QtAV/tests/ao/main.cpp for detail
|
|
*/
|
|
namespace FAV {
|
|
|
|
class AudioFormat;
|
|
class AudioOutputPrivate;
|
|
class Q_AV_EXPORT AudioOutput : public QObject, public AVOutput
|
|
{
|
|
Q_OBJECT
|
|
DPTR_DECLARE_PRIVATE(AudioOutput)
|
|
Q_ENUMS(DeviceFeature)
|
|
Q_FLAGS(DeviceFeatures)
|
|
Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged)
|
|
Q_PROPERTY(bool mute READ isMute WRITE setMute NOTIFY muteChanged)
|
|
Q_PROPERTY(DeviceFeatures deviceFeatures READ deviceFeatures WRITE setDeviceFeatures NOTIFY deviceFeaturesChanged)
|
|
Q_PROPERTY(QStringList backends READ backends WRITE setBackends NOTIFY backendsChanged)
|
|
public:
|
|
/*!
|
|
* \brief DeviceFeature Feature enum
|
|
* Features supported by the audio playback api (we call device or backend here)
|
|
* If a feature is not supported, e.g. SetVolume, then a software implementation is used.
|
|
*/
|
|
enum DeviceFeature {
|
|
NoFeature = 0,
|
|
SetVolume = 1, /// Use backend volume control api rather than software scale. Ignore if backend does not support.
|
|
SetMute = 1 << 1,
|
|
SetSampleRate = 1 << 2, /// NOT IMPLEMENTED
|
|
SetSpeed = 1 << 3, /// NOT IMPLEMENTED
|
|
};
|
|
Q_DECLARE_FLAGS(DeviceFeatures, DeviceFeature)
|
|
/*!
|
|
* \brief backendsAvailable
|
|
* All registered backends in default priority order
|
|
* \return
|
|
*/
|
|
static QStringList backendsAvailable();
|
|
/*!
|
|
* \brief AudioOutput
|
|
* Audio format set to preferred sample format and channel layout
|
|
*/
|
|
AudioOutput(QObject *parent = 0);
|
|
~AudioOutput();
|
|
/*!
|
|
* \brief setBackends
|
|
* set the given backends. Old backend instance and backend() is updated soon if backendsChanged.
|
|
* It is called internally with a default backend names when AudioOutput is created.
|
|
*/
|
|
void setBackends(const QStringList &backendNames = QStringList());
|
|
QStringList backends() const;
|
|
/*!
|
|
* \brief backend
|
|
* backend name currently in use
|
|
*/
|
|
QString backend() const;
|
|
|
|
|
|
QString status() const;
|
|
/*!
|
|
* \brief flush
|
|
* Play the buffered audio data
|
|
* \return
|
|
*/
|
|
void flush();
|
|
/*!
|
|
* \brief clear
|
|
* Clear audio buffers and set time to 0. The default behavior is flush and reset time
|
|
*/
|
|
void clear();
|
|
bool open();
|
|
bool close();
|
|
bool isOpen() const;
|
|
/*!
|
|
* \brief play
|
|
* Play out the given audio data. It may block current thread until the data can be written to audio device
|
|
* for async playback backend, or until the data is completely played for blocking playback backend.
|
|
* \param data Audio data to play
|
|
* \param pts Timestamp for this data. Useful if need A/V sync. Ignore it if only play audio
|
|
* \return false if currently isPaused(), no backend is available or backend failed to play
|
|
*/
|
|
bool play(const QByteArray& data, qreal pts = 0.0);
|
|
/*!
|
|
* \brief pause
|
|
* Pause audio rendering. play() will fail.
|
|
*/
|
|
void pause(bool value);
|
|
bool isPaused() const;
|
|
/*!
|
|
* \brief setAudioFormat
|
|
* Set/Request to use the given \l format. If it's not supported, an preferred format will be used.
|
|
* \param format requested format
|
|
* \return actual format to use. Invalid format if backend is not available
|
|
* NOTE: Check format support may fail for some backends (OpenAL) if it's closed.
|
|
*/
|
|
AudioFormat setAudioFormat(const AudioFormat& format);
|
|
const AudioFormat& requestedFormat() const;
|
|
/*!
|
|
* \brief audioFormat
|
|
* \return actual format for requested format
|
|
*/
|
|
const AudioFormat& audioFormat() const;
|
|
/*!
|
|
* \brief setVolume
|
|
* Set volume level.
|
|
* If SetVolume feature is not set or not supported, software implementation will be used.
|
|
* Call this after open(), because it will call backend api if SetVolume feature is enabled
|
|
* \param volume linear. 1.0: original volume.
|
|
*/
|
|
void setVolume(qreal value);
|
|
qreal volume() const;
|
|
/*!
|
|
* \brief setMute
|
|
* If SetMute feature is not set or not supported, software implementation will be used.
|
|
* Call this after open(), because it will call backend api if SetMute feature is enabled
|
|
*/
|
|
void setMute(bool value = true);
|
|
bool isMute() const;
|
|
/*!
|
|
* \brief setSpeed set audio playing speed
|
|
* Currently only store the value and does nothing else in audio output. You may change sample rate to get the same effect.
|
|
* The speed affects the playing only if audio is available and clock type is
|
|
* audio clock. For example, play a video contains audio without special configurations.
|
|
* To change the playing speed in other cases, use AVPlayer::setSpeed(qreal)
|
|
* \param speed linear. > 0
|
|
* TODO: resample internally
|
|
*/
|
|
void setSpeed(qreal speed);
|
|
qreal speed() const;
|
|
/*!
|
|
* \brief isSupported
|
|
* check \a isSupported(format.sampleFormat()) and \a isSupported(format.channelLayout())
|
|
* \param format
|
|
* \return true if \a format is supported. default is true
|
|
* NOTE: may fail for some backends if it's closed, for example OpenAL
|
|
*/
|
|
bool isSupported(const AudioFormat& format) const;
|
|
/*!
|
|
* \brief bufferSamples
|
|
* Number of samples that audio output accept in 1 buffer. Feed the audio output this size of data every time.
|
|
* Smaller buffer samples gives more buffers for a given data to avoid stutter. But if it's too small, the duration of 1 buffer will be too small to play, for example 1ms. Currently the default value is 512.
|
|
* Some backends(OpenAL) are affected significantly by this property
|
|
*/
|
|
int bufferSamples() const;
|
|
void setBufferSamples(int value);
|
|
int bufferSize() const; /// bufferSamples()*bytesPerSample
|
|
/*!
|
|
* \brief bufferCount
|
|
* Total buffer count. If it's not large enough, playing high sample rate audio may be poor.
|
|
* The default value is 16. TODO: depending on audio format(sample rate?)
|
|
* Some backends(OpenAL) are affected significantly by this property
|
|
*/
|
|
int bufferCount() const;
|
|
void setBufferCount(int value);
|
|
int bufferSizeTotal() const { return bufferCount() * bufferSize();}
|
|
/*!
|
|
* \brief setDeviceFeatures
|
|
* Unsupported features will not be set.
|
|
* You can call this in a backend ctor.
|
|
*/
|
|
void setDeviceFeatures(DeviceFeatures value);
|
|
/*!
|
|
* \brief deviceFeatures
|
|
* \return features set by setFeatures() excluding unsupported features
|
|
*/
|
|
DeviceFeatures deviceFeatures() const;
|
|
/*!
|
|
* \brief supportedDeviceFeatures
|
|
* Supported features of the backend, defined by AudioOutput(DeviceFeatures,AudioOutput&,QObject*) in a backend ctor
|
|
*/
|
|
DeviceFeatures supportedDeviceFeatures() const;
|
|
qreal timestamp() const;
|
|
// timestamp of current playing data
|
|
Q_SIGNALS:
|
|
void volumeChanged(qreal);
|
|
void muteChanged(bool);
|
|
void deviceFeaturesChanged();
|
|
void backendsChanged();
|
|
protected:
|
|
// Store and fill data to audio buffers
|
|
bool receiveData(const QByteArray &data, qreal pts = 0.0);
|
|
/*!
|
|
* \brief waitForNextBuffer
|
|
* wait until you can feed more data
|
|
*/
|
|
bool waitForNextBuffer();
|
|
private Q_SLOTS:
|
|
void reportVolume(qreal value);
|
|
void reportMute(bool value);
|
|
private:
|
|
void onCallback();
|
|
friend class AudioOutputBackend;
|
|
Q_DISABLE_COPY(AudioOutput)
|
|
};
|
|
|
|
} //namespace FAV
|
|
#endif // QAV_AUDIOOUTPUT_H
|