#include "qaudio_mac_p.h"
#include "qaudioinput_mac_p.h"
#include "qaudiodeviceinfo_mac_p.h"
+#include "qaudiohelpers_p.h"
QT_BEGIN_NAMESPACE
m_deviceError(false),
m_audioConverter(0),
m_inputFormat(inputFormat),
- m_outputFormat(outputFormat)
+ m_outputFormat(outputFormat),
+ m_volume(qreal(1.0f))
{
m_maxPeriodSize = maxPeriodSize;
m_periodTime = m_maxPeriodSize / m_outputFormat.mBytesPerFrame * 1000 / m_outputFormat.mSampleRate;
m_audioConverter = 0;
}
}
+
+ m_qFormat = toQAudioFormat(inputFormat); // we adjust volume before conversion
}
~QAudioInputBuffer()
delete m_buffer;
}
+ qreal volume() const
+ {
+ return m_volume;
+ }
+
+ void setVolume(qreal v)
+ {
+ m_volume = v;
+ }
+
qint64 renderFromDevice(AudioUnit audioUnit,
AudioUnitRenderActionFlags* ioActionFlags,
const AudioTimeStamp* inTimeStamp,
inNumberFrames,
m_inputBufferList->audioBufferList());
+ // adjust volume, if necessary
+ if (!qFuzzyCompare(m_volume, qreal(1.0f))) {
+ QAudioHelperInternal::qMultiplySamples(m_volume,
+ m_qFormat,
+ m_inputBufferList->data(), /* input */
+ m_inputBufferList->data(), /* output */
+ m_inputBufferList->bufferSize());
+ }
+
if (m_audioConverter != 0) {
QAudioPacketFeeder feeder(m_inputBufferList);
AudioConverterRef m_audioConverter;
AudioStreamBasicDescription m_inputFormat;
AudioStreamBasicDescription m_outputFormat;
+ QAudioFormat m_qFormat;
+ qreal m_volume;
const static OSStatus as_empty = 'qtem';
errorCode = QAudio::NoError;
stateCode = QAudio::StoppedState;
+ m_volume = qreal(1.0f);
+
intervalTimer = new QTimer(this);
intervalTimer->setInterval(1000);
connect(intervalTimer, SIGNAL(timeout()), SIGNAL(notify()));
streamFormat,
this);
+ audioBuffer->setVolume(m_volume);
audioIO = new QtMultimediaInternal::MacInputDevice(audioBuffer, this);
// Init
startTime = AudioGetCurrentHostTime();
totalFrames = 0;
- audioThreadStart();
-
- stateCode = QAudio::ActiveState;
+ stateCode = QAudio::IdleState;
errorCode = QAudio::NoError;
emit stateChanged(stateCode);
+
+ audioThreadStart();
}
QIODevice* QAudioInputPrivate::start()
startTime = AudioGetCurrentHostTime();
totalFrames = 0;
- audioThreadStart();
-
- stateCode = QAudio::ActiveState;
+ stateCode = QAudio::IdleState;
errorCode = QAudio::NoError;
emit stateChanged(stateCode);
+ audioThreadStart();
+
return op;
}
errorCode = QAudio::NoError;
stateCode = QAudio::StoppedState;
+ audioBuffer->reset();
QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
}
}
int QAudioInputPrivate::bytesReady() const
{
+ if (!audioBuffer)
+ return 0;
return audioBuffer->used();
}
return stateCode;
}
+qreal QAudioInputPrivate::volume() const
+{
+ return m_volume;
+}
+
+void QAudioInputPrivate::setVolume(qreal volume)
+{
+ m_volume = volume;
+ if (audioBuffer)
+ audioBuffer->setVolume(m_volume);
+}
+
+
void QAudioInputPrivate::audioThreadStop()
{
stopTimers();
threadFinished.wakeOne();
}
+void QAudioInputPrivate::audioDeviceActive()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::IdleState) {
+ stateCode = QAudio::ActiveState;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
void QAudioInputPrivate::audioDeviceFull()
{
QMutexLocker lock(&mutex);
if (stateCode == QAudio::ActiveState) {
- audioDeviceStop();
-
errorCode = QAudio::UnderrunError;
stateCode = QAudio::IdleState;
- QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
}
}
inBusNumber,
inNumberFrames);
- if (framesWritten > 0)
+ if (framesWritten > 0) {
d->totalFrames += framesWritten;
- else if (framesWritten == 0)
+ d->audioDeviceActive();
+ } else if (framesWritten == 0)
d->audioDeviceFull();
else if (framesWritten < 0)
d->audioDeviceError();
WavHeader wavHeader(audioFormat);
QVERIFY(wavHeader.write(*audioFile));
+ // Set a large buffer to avoid underruns during QTest::qWaits
+ audioInput.setBufferSize(128*1024);
+
QIODevice* feed = audioInput.start();
// Check that QAudioInput immediately transitions to IdleState
QByteArray buffer(AUDIO_BUFFER, 0);
qint64 len = (audioFormat.sampleRate()*audioFormat.channelCount()*(audioFormat.sampleSize()/8)*2); // 2 seconds
while (totalBytesRead < len) {
- if (audioInput.bytesReady() >= audioInput.periodSize()) {
- qint64 bytesRead = feed->read(buffer.data(), audioInput.periodSize());
- audioFile->write(buffer.constData(),bytesRead);
- totalBytesRead+=bytesRead;
- if (firstBuffer && bytesRead) {
- // Check for transition to ActiveState when data is provided
- QVERIFY2((stateSignal.count() == 1),"didn't emit ActiveState signal on data");
- QVERIFY2((audioInput.state() == QAudio::ActiveState),
- "didn't transition to ActiveState after data");
- QVERIFY2((audioInput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
- firstBuffer = false;
- }
- } else
- QTest::qWait(20);
+ QTRY_VERIFY(audioInput.bytesReady() >= audioInput.periodSize());
+ qint64 bytesRead = feed->read(buffer.data(), audioInput.periodSize());
+ audioFile->write(buffer.constData(),bytesRead);
+ totalBytesRead+=bytesRead;
+ if (firstBuffer && bytesRead) {
+ // Check for transition to ActiveState when data is provided
+ QTRY_VERIFY2((stateSignal.count() == 1),"didn't emit ActiveState signal on data");
+ QVERIFY2((audioInput.state() == QAudio::ActiveState),
+ "didn't transition to ActiveState after data");
+ QVERIFY2((audioInput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
+ firstBuffer = false;
+ }
}
QTest::qWait(1000);
QAudioInput audioInput(audioFormat, this);
audioInput.setNotifyInterval(100);
+ audioInput.setBufferSize(128*1024);
QSignalSpy notifySignal(&audioInput, SIGNAL(notify()));
QSignalSpy stateSignal(&audioInput, SIGNAL(stateChanged(QAudio::State)));
QByteArray buffer(AUDIO_BUFFER, 0);
qint64 len = (audioFormat.sampleRate()*audioFormat.channelCount()*(audioFormat.sampleSize()/8)); // 1 seconds
while (totalBytesRead < len) {
- if (audioInput.bytesReady() >= audioInput.periodSize()) {
- qint64 bytesRead = feed->read(buffer.data(), audioInput.periodSize());
- audioFile->write(buffer.constData(),bytesRead);
- totalBytesRead+=bytesRead;
- if (firstBuffer && bytesRead) {
- // Check for transition to ActiveState when data is provided
- QVERIFY2((stateSignal.count() == 1),"didn't emit ActiveState signal on data");
- QVERIFY2((audioInput.state() == QAudio::ActiveState),
- "didn't transition to ActiveState after data");
- QVERIFY2((audioInput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
- firstBuffer = false;
- }
- } else
- QTest::qWait(20);
+ QTRY_VERIFY(audioInput.bytesReady() >= audioInput.periodSize());
+ qint64 bytesRead = feed->read(buffer.data(), audioInput.periodSize());
+ audioFile->write(buffer.constData(),bytesRead);
+ totalBytesRead+=bytesRead;
+ if (firstBuffer && bytesRead) {
+ // Check for transition to ActiveState when data is provided
+ QTRY_VERIFY2((stateSignal.count() == 1),"didn't emit ActiveState signal on data");
+ QVERIFY2((audioInput.state() == QAudio::ActiveState),
+ "didn't transition to ActiveState after data");
+ QVERIFY2((audioInput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after start()");
+ firstBuffer = false;
+ }
}
stateSignal.clear();
QVERIFY(audioInput.elapsedUSecs() > elapsedUs);
QVERIFY(audioInput.processedUSecs() == processedUs);
- audioInput.resume();
+ // Drain any data, in case we run out of space when resuming
+ while (audioInput.bytesReady() >= audioInput.periodSize()) {
+ feed->read(buffer.data(), audioInput.periodSize());
+ }
- // Give backends running in separate threads a chance to resume.
- QTest::qWait(100);
+ audioInput.resume();
// Check that QAudioInput immediately transitions to Active or IdleState
- QVERIFY2((stateSignal.count() > 0),"didn't emit signals on resume()");
+ QTRY_VERIFY2((stateSignal.count() > 0),"didn't emit signals on resume()");
QVERIFY2((audioInput.state() == QAudio::ActiveState || audioInput.state() == QAudio::IdleState),
"didn't transition to ActiveState or IdleState after resume()");
QVERIFY2((audioInput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after resume()");
// Read another seconds worth
totalBytesRead = 0;
firstBuffer = true;
- while (totalBytesRead < len) {
- if (audioInput.bytesReady() >= audioInput.periodSize()) {
- qint64 bytesRead = feed->read(buffer.data(), audioInput.periodSize());
- audioFile->write(buffer.constData(),bytesRead);
- totalBytesRead+=bytesRead;
- } else
- QTest::qWait(20);
+ while (totalBytesRead < len && audioInput.state() != QAudio::StoppedState) {
+ QTRY_VERIFY(audioInput.bytesReady() >= audioInput.periodSize());
+ qint64 bytesRead = feed->read(buffer.data(), audioInput.periodSize());
+ audioFile->write(buffer.constData(),bytesRead);
+ totalBytesRead+=bytesRead;
}
stateSignal.clear();
stateSignal.clear();
audioInput.reset();
- QTRY_VERIFY2((stateSignal.count() == 1),"didn't emit StoppedState signal after reset()");
+ QTRY_VERIFY2((stateSignal.count() >= 1),"didn't emit StoppedState signal after reset()");
QVERIFY2((audioInput.state() == QAudio::StoppedState), "didn't transitions to StoppedState after reset()");
QVERIFY2((audioInput.bytesReady() == 0), "buffer not cleared after reset()");
}