2 * Copyright (C) 2011-2012 Juho Vähä-Herttua
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
15 #include "audiooutput.h"
21 #define BUFFER_SIZE (64*1024)
23 AudioOutput::AudioOutput(QObject
*parent
) :
31 bool AudioOutput::init(int bits
, int channels
, int samplerate
)
40 m_format
.setSampleSize(bits
);
41 m_format
.setChannels(channels
);
42 m_format
.setFrequency(samplerate
);
43 m_format
.setCodec("audio/pcm");
44 m_format
.setByteOrder(QAudioFormat::LittleEndian
);
45 m_format
.setSampleType(QAudioFormat::SignedInt
);
47 m_initialized
= setDevice(QAudioDeviceInfo::defaultOutputDevice());
51 bool AudioOutput::setDevice(QAudioDeviceInfo deviceInfo
)
53 if (!deviceInfo
.isFormatSupported(m_format
)) {
54 qDebug() << "Format not supported!";
57 m_deviceInfo
= deviceInfo
;
62 void AudioOutput::reinit()
65 if (m_output
&& m_output
->state() != QAudio::StoppedState
) {
70 // Reinitialize audio output
73 m_output
= new QAudioOutput(m_deviceInfo
, m_format
, this);
75 // Set constant values to new audio output
76 connect(m_output
, SIGNAL(notify()), SLOT(notified()));
77 connect(m_output
, SIGNAL(stateChanged(QAudio::State
)), SLOT(stateChanged(QAudio::State
)));
83 void AudioOutput::start()
85 if (m_output
== 0 || m_output
->state() != QAudio::StoppedState
) {
88 this->open(QIODevice::ReadOnly
);
90 m_output
->start(this);
94 void AudioOutput::setVolume(float volume
)
99 void AudioOutput::output(const QByteArray
& data
)
101 if (m_output
&& m_output
->state() != QAudio::StoppedState
) {
102 // Append input data to the end of buffer
103 m_buffer
.append(data
);
105 // Check if our buffer has grown too large
106 if (m_buffer
.length() > 2*BUFFER_SIZE
) {
107 // There could be a better way to handle this
111 // If audio is suspended and buffer is full, resume
112 if (m_output
->state() == QAudio::SuspendedState
) {
113 if (m_buffer
.length() >= BUFFER_SIZE
) {
114 qDebug() << "Resuming...";
121 void AudioOutput::flush()
123 // Flushing buffers is a bit tricky...
124 // Don't modify this unless you're sure
130 void AudioOutput::stop()
132 if (m_output
&& m_output
->state() != QAudio::StoppedState
) {
140 static void apply_s16le_volume(float volume
, uchar
*data
, int datalen
)
142 int samples
= datalen
/2;
143 float mult
= pow(10.0,0.05*volume
);
145 for (int i
=0; i
<samples
; i
++) {
146 qint16 val
= qFromLittleEndian
<qint16
>(data
+i
*2)*mult
;
147 qToLittleEndian
<qint16
>(val
, data
+i
*2);
151 qint64
AudioOutput::readData(char *data
, qint64 maxlen
)
153 // Calculate output length, always full samples
154 int outlen
= qMin(m_buffer
.length(), (int)maxlen
);
159 memcpy(data
, m_buffer
.data(), outlen
);
160 apply_s16le_volume(m_volume
, (uchar
*)data
, outlen
);
161 m_buffer
.remove(0, outlen
);
165 qint64
AudioOutput::writeData(const char *data
, qint64 len
)
173 qint64
AudioOutput::bytesAvailable() const
175 return m_buffer
.length() + QIODevice::bytesAvailable();
178 bool AudioOutput::isSequential() const
183 void AudioOutput::notified()
187 void AudioOutput::stateChanged(QAudio::State state
)
189 // Start buffering again in case of underrun...
190 // Required on Windows, otherwise it stalls idle
191 if (state
== QAudio::IdleState
&& m_output
->error() == QAudio::UnderrunError
) {
192 // This check is required, because Mac OS X underruns often
193 if (m_buffer
.length() < BUFFER_SIZE
) {
197 qWarning() << "state = " << state
;