1 #include "audiooutput.h"
7 #define BUFFER_SIZE (64*1024)
9 AudioOutput::AudioOutput(QObject
*parent
) :
17 bool AudioOutput::init(int bits
, int channels
, int samplerate
)
26 m_format
.setSampleSize(bits
);
27 m_format
.setChannels(channels
);
28 m_format
.setFrequency(samplerate
);
29 m_format
.setCodec("audio/pcm");
30 m_format
.setByteOrder(QAudioFormat::LittleEndian
);
31 m_format
.setSampleType(QAudioFormat::SignedInt
);
33 m_initialized
= setDevice(QAudioDeviceInfo::defaultOutputDevice());
37 bool AudioOutput::setDevice(QAudioDeviceInfo deviceInfo
)
39 if (!deviceInfo
.isFormatSupported(m_format
)) {
40 qDebug() << "Format not supported!";
43 m_deviceInfo
= deviceInfo
;
48 void AudioOutput::reinit()
51 if (m_output
&& m_output
->state() != QAudio::StoppedState
) {
56 // Reinitialize audio output
59 m_output
= new QAudioOutput(m_deviceInfo
, m_format
, this);
61 // Set constant values to new audio output
62 connect(m_output
, SIGNAL(notify()), SLOT(notified()));
63 connect(m_output
, SIGNAL(stateChanged(QAudio::State
)), SLOT(stateChanged(QAudio::State
)));
69 void AudioOutput::start()
71 if (m_output
== 0 || m_output
->state() != QAudio::StoppedState
) {
74 this->open(QIODevice::ReadOnly
);
76 m_output
->start(this);
80 void AudioOutput::setVolume(float volume
)
85 void AudioOutput::output(const char *data
, int datalen
)
87 if (m_output
&& m_output
->state() != QAudio::StoppedState
) {
88 // Append input data to the end of buffer
89 m_buffer
.append(data
, datalen
);
91 // Check if our buffer has grown too large
92 if (m_buffer
.length() > 2*BUFFER_SIZE
) {
93 // There could be a better way to handle this
97 // If audio is suspended and buffer is full, resume
98 if (m_output
->state() == QAudio::SuspendedState
) {
99 if (m_buffer
.length() >= BUFFER_SIZE
) {
100 qDebug() << "Resuming...";
107 void AudioOutput::flush()
109 // Flushing buffers is a bit tricky...
110 // Don't modify this unless you're sure
116 void AudioOutput::stop()
118 if (m_output
&& m_output
->state() != QAudio::StoppedState
) {
126 static void apply_s16le_volume(float volume
, uchar
*data
, int datalen
)
128 int samples
= datalen
/2;
129 float mult
= pow(10.0,0.05*volume
);
131 for (int i
=0; i
<samples
; i
++) {
132 qint16 val
= qFromLittleEndian
<qint16
>(data
+i
*2)*mult
;
133 qToLittleEndian
<qint16
>(val
, data
+i
*2);
137 qint64
AudioOutput::readData(char *data
, qint64 maxlen
)
139 // Calculate output length, always full samples
140 int outlen
= qMin(m_buffer
.length(), (int)maxlen
);
145 memcpy(data
, m_buffer
.data(), outlen
);
146 apply_s16le_volume(m_volume
, (uchar
*)data
, outlen
);
147 m_buffer
.remove(0, outlen
);
151 qint64
AudioOutput::writeData(const char *data
, qint64 len
)
159 qint64
AudioOutput::bytesAvailable() const
161 return m_buffer
.length() + QIODevice::bytesAvailable();
164 bool AudioOutput::isSequential() const
169 void AudioOutput::notified()
173 void AudioOutput::stateChanged(QAudio::State state
)
175 // Start buffering again in case of underrun...
176 // Required on Windows, otherwise it stalls idle
177 if (state
== QAudio::IdleState
&& m_output
->error() == QAudio::UnderrunError
) {
178 // This check is required, because Mac OS X underruns often
179 if (m_buffer
.length() < BUFFER_SIZE
) {
183 qWarning() << "state = " << state
;