summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorQt Continuous Integration System <qt-info@nokia.com>2010-02-17 21:55:18 (GMT)
committerQt Continuous Integration System <qt-info@nokia.com>2010-02-17 21:55:18 (GMT)
commit9eacc56619ce471a9777f88c89f64ca95cd6ae63 (patch)
treeb52b46a26a04889145a30339da28e5aa99756b1c /examples
parentfd3f9dd0f31efeea3aa0ec28b54c70d85712c7ba (diff)
parent54b20c491f7e182f6b98f65b7e9e8e68286d6109 (diff)
downloadQt-9eacc56619ce471a9777f88c89f64ca95cd6ae63.zip
Qt-9eacc56619ce471a9777f88c89f64ca95cd6ae63.tar.gz
Qt-9eacc56619ce471a9777f88c89f64ca95cd6ae63.tar.bz2
Merge branch 'qt-master-from-4.6' of scm.dev.nokia.troll.no:qt/qt-integration into master-integration
* 'qt-master-from-4.6' of scm.dev.nokia.troll.no:qt/qt-integration: (249 commits) Fixed autotest failure in tst_QGraphicsScene::render on Maemo. Changed function names in audio input example to clarify meaning Tidied up debug output in audio input example Removed redundant strings from audio input example Cleaned up memory management in audio input example Changed variable names in audio input example to match Qt code style Made level calculation in audio input example work for all formats Removed unused variable from audio input example Update suspend/resume button label in audio input example Changed function names in audio output example to clarify meaning Cleaned up implementation of audio output example Tidied up debug output in audio output example Removed redundant strings from audio output example Cleaned up memory management in audio output example Changed variable names in audio output example to match Qt code style Made data generation in audio output example work for all formats Update suspend/resume button label in audio output example Added missing override in audio output example QLocalSocket::isValid on Windows must check for broken connection Fix an issue with the error signal in a callWithCallback not being ...
Diffstat (limited to 'examples')
-rw-r--r--examples/multimedia/audioinput/audioinput.cpp309
-rw-r--r--examples/multimedia/audioinput/audioinput.h60
-rw-r--r--examples/multimedia/audiooutput/audiooutput.cpp345
-rw-r--r--examples/multimedia/audiooutput/audiooutput.h68
4 files changed, 443 insertions, 339 deletions
diff --git a/examples/multimedia/audioinput/audioinput.cpp b/examples/multimedia/audioinput/audioinput.cpp
index fbf4dc4..8a97640 100644
--- a/examples/multimedia/audioinput/audioinput.cpp
+++ b/examples/multimedia/audioinput/audioinput.cpp
@@ -48,16 +48,47 @@
#include <QAudioDeviceInfo>
#include <QAudioInput>
+
+#include <QtCore/qendian.h>
+
#include "audioinput.h"
-#define BUFFER_SIZE 4096
+const QString InputTest::PushModeLabel(tr("Enable push mode"));
+const QString InputTest::PullModeLabel(tr("Enable pull mode"));
+const QString InputTest::SuspendLabel(tr("Suspend recording"));
+const QString InputTest::ResumeLabel(tr("Resume recording"));
-AudioInfo::AudioInfo(QObject *parent, QAudioInput *device)
- :QIODevice(parent)
-{
- input = device;
+const int BufferSize = 4096;
+
+AudioInfo::AudioInfo(const QAudioFormat &format, QObject *parent)
+ : QIODevice(parent)
+ , m_format(format)
+ , m_maxAmplitude(0)
+ , m_level(0.0)
- m_maxValue = 0;
+{
+ switch (m_format.sampleSize()) {
+ case 8:
+ switch (m_format.sampleType()) {
+ case QAudioFormat::UnSignedInt:
+ m_maxAmplitude = 255;
+ break;
+ case QAudioFormat::SignedInt:
+ m_maxAmplitude = 127;
+ break;
+ }
+ break;
+ case 16:
+ switch (m_format.sampleType()) {
+ case QAudioFormat::UnSignedInt:
+ m_maxAmplitude = 65535;
+ break;
+ case QAudioFormat::SignedInt:
+ m_maxAmplitude = 32767;
+ break;
+ }
+ break;
+ }
}
AudioInfo::~AudioInfo()
@@ -84,48 +115,56 @@ qint64 AudioInfo::readData(char *data, qint64 maxlen)
qint64 AudioInfo::writeData(const char *data, qint64 len)
{
- int samples = len/2; // 2 bytes per sample
- int maxAmp = 32768; // max for S16 samples
- bool clipping = false;
-
- m_maxValue = 0;
-
- qint16 *s = (qint16*)data;
-
- // sample format is S16LE, only!
-
- for (int i = 0; i < samples; ++i) {
- qint16 sample = *s;
- s++;
- if (abs(sample) > m_maxValue) m_maxValue = abs(sample);
+ if (m_maxAmplitude) {
+ Q_ASSERT(m_format.sampleSize() % 8 == 0);
+ const int channelBytes = m_format.sampleSize() / 8;
+ const int sampleBytes = m_format.channels() * channelBytes;
+ Q_ASSERT(len % sampleBytes == 0);
+ const int numSamples = len / sampleBytes;
+
+ quint16 maxValue = 0;
+ const unsigned char *ptr = reinterpret_cast<const unsigned char *>(data);
+
+ for (int i = 0; i < numSamples; ++i) {
+ for(int j = 0; j < m_format.channels(); ++j) {
+ quint16 value = 0;
+
+ if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::UnSignedInt) {
+ value = *reinterpret_cast<const quint8*>(ptr);
+ } else if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::SignedInt) {
+ value = qAbs(*reinterpret_cast<const qint8*>(ptr));
+ } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::UnSignedInt) {
+ if (m_format.byteOrder() == QAudioFormat::LittleEndian)
+ value = qFromLittleEndian<quint16>(ptr);
+ else
+ value = qFromBigEndian<quint16>(ptr);
+ } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::SignedInt) {
+ if (m_format.byteOrder() == QAudioFormat::LittleEndian)
+ value = qAbs(qFromLittleEndian<qint16>(ptr));
+ else
+ value = qAbs(qFromBigEndian<qint16>(ptr));
+ }
+
+ maxValue = qMax(value, maxValue);
+ ptr += channelBytes;
+ }
+ }
+
+ maxValue = qMin(maxValue, m_maxAmplitude);
+ m_level = qreal(maxValue) / m_maxAmplitude;
}
- // check for clipping
- if (m_maxValue >= (maxAmp - 1))
- clipping = true;
-
- float value = ((float)m_maxValue/(float)maxAmp);
- if (clipping)
- m_maxValue = 100;
- else
- m_maxValue = (int)(value*100);
emit update();
-
return len;
}
-int AudioInfo::LinearMax()
-{
- return m_maxValue;
-}
-
RenderArea::RenderArea(QWidget *parent)
: QWidget(parent)
{
setBackgroundRole(QPalette::Base);
setAutoFillBackground(true);
- level = 0;
+ m_level = 0;
setMinimumHeight(30);
setMinimumWidth(200);
}
@@ -139,12 +178,12 @@ void RenderArea::paintEvent(QPaintEvent * /* event */)
painter.viewport().top()+10,
painter.viewport().right()-20,
painter.viewport().bottom()-20));
- if (level == 0)
+ if (m_level == 0.0)
return;
painter.setPen(Qt::red);
- int pos = ((painter.viewport().right()-20)-(painter.viewport().left()+11))*level/100;
+ int pos = ((painter.viewport().right()-20)-(painter.viewport().left()+11))*m_level;
for (int i = 0; i < 10; ++i) {
int x1 = painter.viewport().left()+11;
int y1 = painter.viewport().top()+10+i;
@@ -157,156 +196,174 @@ void RenderArea::paintEvent(QPaintEvent * /* event */)
}
}
-void RenderArea::setLevel(int value)
+void RenderArea::setLevel(qreal value)
{
- level = value;
+ m_level = value;
repaint();
}
InputTest::InputTest()
+ : m_canvas(0)
+ , m_modeButton(0)
+ , m_suspendResumeButton(0)
+ , m_deviceBox(0)
+ , m_audioInfo(0)
+ , m_audioInput(0)
+ , m_input(0)
+ , m_pullMode(false)
+ , m_buffer(BufferSize, 0)
{
- QWidget *window = new QWidget;
- QVBoxLayout* layout = new QVBoxLayout;
+ initializeWindow();
+ initializeAudio();
+}
+
+InputTest::~InputTest() {}
+
+void InputTest::initializeWindow()
+{
+ QScopedPointer<QWidget> window(new QWidget);
+ QScopedPointer<QVBoxLayout> layout(new QVBoxLayout);
- canvas = new RenderArea;
- layout->addWidget(canvas);
+ m_canvas = new RenderArea(this);
+ layout->addWidget(m_canvas);
- deviceBox = new QComboBox(this);
+ m_deviceBox = new QComboBox(this);
QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
for(int i = 0; i < devices.size(); ++i)
- deviceBox->addItem(devices.at(i).deviceName(), qVariantFromValue(devices.at(i)));
+ m_deviceBox->addItem(devices.at(i).deviceName(), qVariantFromValue(devices.at(i)));
- connect(deviceBox, SIGNAL(activated(int)), SLOT(deviceChanged(int)));
- layout->addWidget(deviceBox);
+ connect(m_deviceBox, SIGNAL(activated(int)), SLOT(deviceChanged(int)));
+ layout->addWidget(m_deviceBox);
- button = new QPushButton(this);
- button->setText(tr("Click for Push Mode"));
- connect(button, SIGNAL(clicked()), SLOT(toggleMode()));
- layout->addWidget(button);
+ m_modeButton = new QPushButton(this);
+ m_modeButton->setText(PushModeLabel);
+ connect(m_modeButton, SIGNAL(clicked()), SLOT(toggleMode()));
+ layout->addWidget(m_modeButton);
- button2 = new QPushButton(this);
- button2->setText(tr("Click To Suspend"));
- connect(button2, SIGNAL(clicked()), SLOT(toggleSuspend()));
- layout->addWidget(button2);
+ m_suspendResumeButton = new QPushButton(this);
+ m_suspendResumeButton->setText(SuspendLabel);
+ connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspend()));
+ layout->addWidget(m_suspendResumeButton);
- window->setLayout(layout);
- setCentralWidget(window);
- window->show();
+ window->setLayout(layout.data());
+ layout.take(); // ownership transferred
- buffer = new char[BUFFER_SIZE];
+ setCentralWidget(window.data());
+ QWidget *const windowPtr = window.take(); // ownership transferred
+ windowPtr->show();
+}
- pullMode = true;
+void InputTest::initializeAudio()
+{
+ m_pullMode = true;
- format.setFrequency(8000);
- format.setChannels(1);
- format.setSampleSize(16);
- format.setSampleType(QAudioFormat::SignedInt);
- format.setByteOrder(QAudioFormat::LittleEndian);
- format.setCodec("audio/pcm");
+ m_format.setFrequency(8000);
+ m_format.setChannels(1);
+ m_format.setSampleSize(16);
+ m_format.setSampleType(QAudioFormat::SignedInt);
+ m_format.setByteOrder(QAudioFormat::LittleEndian);
+ m_format.setCodec("audio/pcm");
QAudioDeviceInfo info(QAudioDeviceInfo::defaultInputDevice());
- if (!info.isFormatSupported(format)) {
- qWarning()<<"default format not supported try to use nearest";
- format = info.nearestFormat(format);
+ if (!info.isFormatSupported(m_format)) {
+ qWarning() << "Default format not supported - trying to use nearest";
+ m_format = info.nearestFormat(m_format);
}
- if(format.sampleSize() != 16) {
- qWarning()<<"audio device doesn't support 16 bit samples, example cannot run";
- audioInput = 0;
- button->setDisabled(true);
- button2->setDisabled(true);
- return;
- }
+ m_audioInfo = new AudioInfo(m_format, this);
+ connect(m_audioInfo, SIGNAL(update()), SLOT(refreshDisplay()));
- audioInput = new QAudioInput(format,this);
- connect(audioInput, SIGNAL(notify()), SLOT(status()));
- connect(audioInput, SIGNAL(stateChanged(QAudio::State)), SLOT(state(QAudio::State)));
- audioinfo = new AudioInfo(this,audioInput);
- connect(audioinfo, SIGNAL(update()), SLOT(refreshDisplay()));
- audioinfo->start();
- audioInput->start(audioinfo);
+ createAudioInput();
}
-InputTest::~InputTest() {}
+void InputTest::createAudioInput()
+{
-void InputTest::status()
+ m_audioInput = new QAudioInput(m_device, m_format, this);
+ connect(m_audioInput, SIGNAL(notify()), SLOT(notified()));
+ connect(m_audioInput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State)));
+ m_audioInfo->start();
+ m_audioInput->start(m_audioInfo);
+}
+
+void InputTest::notified()
{
- qWarning()<<"bytesReady = "<<audioInput->bytesReady()<<" bytes, elapsedUSecs = "<<audioInput->elapsedUSecs()<<", processedUSecs = "<<audioInput->processedUSecs();
+ qWarning() << "bytesReady = " << m_audioInput->bytesReady()
+ << ", " << "elapsedUSecs = " <<m_audioInput->elapsedUSecs()
+ << ", " << "processedUSecs = "<<m_audioInput->processedUSecs();
}
void InputTest::readMore()
{
- if(!audioInput)
+ if(!m_audioInput)
return;
- qint64 len = audioInput->bytesReady();
+ qint64 len = m_audioInput->bytesReady();
if(len > 4096)
len = 4096;
- qint64 l = input->read(buffer,len);
+ qint64 l = m_input->read(m_buffer.data(), len);
if(l > 0) {
- audioinfo->write(buffer,l);
+ m_audioInfo->write(m_buffer.constData(), l);
}
}
void InputTest::toggleMode()
{
// Change bewteen pull and push modes
- audioInput->stop();
+ m_audioInput->stop();
- if (pullMode) {
- button->setText(tr("Click for Pull Mode"));
- input = audioInput->start();
- connect(input, SIGNAL(readyRead()), SLOT(readMore()));
- pullMode = false;
+ if (m_pullMode) {
+ m_modeButton->setText(PullModeLabel);
+ m_input = m_audioInput->start();
+ connect(m_input, SIGNAL(readyRead()), SLOT(readMore()));
+ m_pullMode = false;
} else {
- button->setText(tr("Click for Push Mode"));
- pullMode = true;
- audioInput->start(audioinfo);
+ m_modeButton->setText(PushModeLabel);
+ m_pullMode = true;
+ m_audioInput->start(m_audioInfo);
}
+
+ m_suspendResumeButton->setText(SuspendLabel);
}
void InputTest::toggleSuspend()
{
// toggle suspend/resume
- if(audioInput->state() == QAudio::SuspendedState) {
+ if(m_audioInput->state() == QAudio::SuspendedState) {
qWarning() << "status: Suspended, resume()";
- audioInput->resume();
- button2->setText("Click To Suspend");
- } else if (audioInput->state() == QAudio::ActiveState) {
+ m_audioInput->resume();
+ m_suspendResumeButton->setText(SuspendLabel);
+ } else if (m_audioInput->state() == QAudio::ActiveState) {
qWarning() << "status: Active, suspend()";
- audioInput->suspend();
- button2->setText("Click To Resume");
- } else if (audioInput->state() == QAudio::StoppedState) {
+ m_audioInput->suspend();
+ m_suspendResumeButton->setText(ResumeLabel);
+ } else if (m_audioInput->state() == QAudio::StoppedState) {
qWarning() << "status: Stopped, resume()";
- audioInput->resume();
- button2->setText("Click To Suspend");
- } else if (audioInput->state() == QAudio::IdleState) {
+ m_audioInput->resume();
+ m_suspendResumeButton->setText(SuspendLabel);
+ } else if (m_audioInput->state() == QAudio::IdleState) {
qWarning() << "status: IdleState";
}
}
-void InputTest::state(QAudio::State state)
+void InputTest::stateChanged(QAudio::State state)
{
- qWarning() << " state=" << state;
+ qWarning() << "state = " << state;
}
void InputTest::refreshDisplay()
{
- canvas->setLevel(audioinfo->LinearMax());
- canvas->repaint();
+ m_canvas->setLevel(m_audioInfo->level());
+ m_canvas->repaint();
}
-void InputTest::deviceChanged(int idx)
+void InputTest::deviceChanged(int index)
{
- audioinfo->stop();
- audioInput->stop();
- audioInput->disconnect(this);
- delete audioInput;
-
- device = deviceBox->itemData(idx).value<QAudioDeviceInfo>();
- audioInput = new QAudioInput(device, format, this);
- connect(audioInput, SIGNAL(notify()), SLOT(status()));
- connect(audioInput, SIGNAL(stateChanged(QAudio::State)), SLOT(state(QAudio::State)));
- audioinfo->start();
- audioInput->start(audioinfo);
+ m_audioInfo->stop();
+ m_audioInput->stop();
+ m_audioInput->disconnect(this);
+ delete m_audioInput;
+
+ m_device = m_deviceBox->itemData(index).value<QAudioDeviceInfo>();
+ createAudioInput();
}
diff --git a/examples/multimedia/audioinput/audioinput.h b/examples/multimedia/audioinput/audioinput.h
index abe2be1..f87c682 100644
--- a/examples/multimedia/audioinput/audioinput.h
+++ b/examples/multimedia/audioinput/audioinput.h
@@ -45,6 +45,7 @@
#include <QMainWindow>
#include <QPushButton>
#include <QComboBox>
+#include <QByteArray>
#include <qaudioinput.h>
@@ -52,21 +53,21 @@ class AudioInfo : public QIODevice
{
Q_OBJECT
public:
- AudioInfo(QObject *parent, QAudioInput *device);
+ AudioInfo(const QAudioFormat &format, QObject *parent);
~AudioInfo();
void start();
void stop();
- int LinearMax();
+ qreal level() const { return m_level; }
qint64 readData(char *data, qint64 maxlen);
qint64 writeData(const char *data, qint64 len);
- QAudioInput *input;
-
private:
- int m_maxValue;
+ const QAudioFormat m_format;
+ quint16 m_maxAmplitude;
+ qreal m_level; // 0.0 <= m_level <= 1.0
signals:
void update();
@@ -80,14 +81,14 @@ class RenderArea : public QWidget
public:
RenderArea(QWidget *parent = 0);
- void setLevel(int value);
+ void setLevel(qreal value);
protected:
void paintEvent(QPaintEvent *event);
private:
- int level;
- QPixmap pixmap;
+ qreal m_level;
+ QPixmap m_pixmap;
};
class InputTest : public QMainWindow
@@ -97,29 +98,38 @@ public:
InputTest();
~InputTest();
+private:
+ void initializeWindow();
+ void initializeAudio();
+ void createAudioInput();
+
private slots:
void refreshDisplay();
- void status();
+ void notified();
void readMore();
void toggleMode();
void toggleSuspend();
- void state(QAudio::State s);
- void deviceChanged(int idx);
+ void stateChanged(QAudio::State state);
+ void deviceChanged(int index);
private:
- AudioInfo *audioinfo;
- QAudioDeviceInfo device;
- QAudioFormat format;
- QAudioInput *audioInput;
- QIODevice *input;
- RenderArea *canvas;
-
- bool pullMode;
-
- QPushButton *button;
- QPushButton *button2;
- QComboBox *deviceBox;
-
- char *buffer;
+ // Owned by layout
+ RenderArea *m_canvas;
+ QPushButton *m_modeButton;
+ QPushButton *m_suspendResumeButton;
+ QComboBox *m_deviceBox;
+
+ AudioInfo *m_audioInfo;
+ QAudioDeviceInfo m_device;
+ QAudioFormat m_format;
+ QAudioInput *m_audioInput;
+ QIODevice *m_input;
+ bool m_pullMode;
+ QByteArray m_buffer;
+
+ static const QString PushModeLabel;
+ static const QString PullModeLabel;
+ static const QString SuspendLabel;
+ static const QString ResumeLabel;
};
diff --git a/examples/multimedia/audiooutput/audiooutput.cpp b/examples/multimedia/audiooutput/audiooutput.cpp
index b44accd..4866d36 100644
--- a/examples/multimedia/audiooutput/audiooutput.cpp
+++ b/examples/multimedia/audiooutput/audiooutput.cpp
@@ -44,30 +44,34 @@
#include <QAudioOutput>
#include <QAudioDeviceInfo>
+#include <QtCore/qmath.h>
+#include <QtCore/qendian.h>
#include "audiooutput.h"
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
+const QString AudioTest::PushModeLabel(tr("Enable push mode"));
+const QString AudioTest::PullModeLabel(tr("Enable pull mode"));
+const QString AudioTest::SuspendLabel(tr("Suspend playback"));
+const QString AudioTest::ResumeLabel(tr("Resume playback"));
-#define SECONDS 1
-#define FREQ 600
-#define SYSTEM_FREQ 44100
+const int DurationSeconds = 1;
+const int ToneFrequencyHz = 600;
+const int DataFrequencyHz = 44100;
+const int BufferSize = 32768;
-Generator::Generator(QObject *parent)
- :QIODevice( parent )
+
+Generator::Generator(const QAudioFormat &format,
+ qint64 durationUs,
+ int frequency,
+ QObject *parent)
+ : QIODevice(parent)
+ , m_pos(0)
{
- finished = false;
- buffer = new char[SECONDS*SYSTEM_FREQ*4+1000];
- t=buffer;
- len=fillData(t,FREQ,SECONDS); /* mono FREQHz sine */
- pos = 0;
- total = len;
+ generateData(format, durationUs, frequency);
}
Generator::~Generator()
{
- delete [] buffer;
+
}
void Generator::start()
@@ -77,47 +81,65 @@ void Generator::start()
void Generator::stop()
{
+ m_pos = 0;
close();
}
-int Generator::putShort(char *t, unsigned int value)
+void Generator::generateData(const QAudioFormat &format, qint64 durationUs, int frequency)
{
- *(unsigned char *)(t++)=value&255;
- *(unsigned char *)(t)=(value/256)&255;
- return 2;
-}
-
-int Generator::fillData(char *start, int frequency, int seconds)
-{
- int i, len=0;
- int value;
- for(i=0; i<seconds*SYSTEM_FREQ; i++) {
- value=(int)(32767.0*sin(2.0*M_PI*((double)(i))*(double)(frequency)/SYSTEM_FREQ));
- putShort(start, value);
- start += 4;
- len+=2;
+ const int channelBytes = format.sampleSize() / 8;
+ const int sampleBytes = format.channels() * channelBytes;
+
+ qint64 length = (format.frequency() * format.channels() * (format.sampleSize() / 8))
+ * durationUs / 100000;
+
+ Q_ASSERT(length % sampleBytes == 0);
+ Q_UNUSED(sampleBytes) // suppress warning in release builds
+
+ m_buffer.resize(length);
+ unsigned char *ptr = reinterpret_cast<unsigned char *>(m_buffer.data());
+ int sampleIndex = 0;
+
+ while (length) {
+ const qreal x = qSin(2 * M_PI * frequency * qreal(sampleIndex % format.frequency()) / format.frequency());
+ for (int i=0; i<format.channels(); ++i) {
+ if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::UnSignedInt) {
+ const quint8 value = static_cast<quint8>((1.0 + x) / 2 * 255);
+ *reinterpret_cast<quint8*>(ptr) = value;
+ } else if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::SignedInt) {
+ const qint8 value = static_cast<qint8>(x * 127);
+ *reinterpret_cast<quint8*>(ptr) = value;
+ } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::UnSignedInt) {
+ quint16 value = static_cast<quint16>((1.0 + x) / 2 * 65535);
+ if (format.byteOrder() == QAudioFormat::LittleEndian)
+ qToLittleEndian<quint16>(value, ptr);
+ else
+ qToBigEndian<quint16>(value, ptr);
+ } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt) {
+ qint16 value = static_cast<qint16>(x * 32767);
+ if (format.byteOrder() == QAudioFormat::LittleEndian)
+ qToLittleEndian<qint16>(value, ptr);
+ else
+ qToBigEndian<qint16>(value, ptr);
+ }
+
+ ptr += channelBytes;
+ length -= channelBytes;
+ }
+ ++sampleIndex;
}
- return len;
}
-qint64 Generator::readData(char *data, qint64 maxlen)
+qint64 Generator::readData(char *data, qint64 len)
{
- int len = maxlen;
- if (len > 16384)
- len = 16384;
-
- if (len < (SECONDS*SYSTEM_FREQ*2)-pos) {
- // Normal
- memcpy(data,t+pos,len);
- pos+=len;
- return len;
- } else {
- // Whats left and reset to start
- qint64 left = (SECONDS*SYSTEM_FREQ*2)-pos;
- memcpy(data,t+pos,left);
- pos=0;
- return left;
+ qint64 total = 0;
+ while (len - total) {
+ const qint64 chunk = qMin((m_buffer.size() - m_pos), len - total);
+ memcpy(data, m_buffer.constData() + m_pos, chunk);
+ m_pos = (m_pos + chunk) % m_buffer.size();
+ total += chunk;
}
+ return total;
}
qint64 Generator::writeData(const char *data, qint64 len)
@@ -128,158 +150,165 @@ qint64 Generator::writeData(const char *data, qint64 len)
return 0;
}
-AudioTest::AudioTest()
+qint64 Generator::bytesAvailable() const
{
- QWidget *window = new QWidget;
- QVBoxLayout* layout = new QVBoxLayout;
-
- deviceBox = new QComboBox(this);
- foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput))
- deviceBox->addItem(deviceInfo.deviceName(), qVariantFromValue(deviceInfo));
- connect(deviceBox,SIGNAL(activated(int)),SLOT(deviceChanged(int)));
- layout->addWidget(deviceBox);
-
- button = new QPushButton(this);
- button->setText(tr("Click for Push Mode"));
- connect(button,SIGNAL(clicked()),SLOT(toggle()));
- layout->addWidget(button);
-
- button2 = new QPushButton(this);
- button2->setText(tr("Click To Suspend"));
- connect(button2,SIGNAL(clicked()),SLOT(togglePlay()));
- layout->addWidget(button2);
-
- window->setLayout(layout);
- setCentralWidget(window);
- window->show();
+ return m_buffer.size() + QIODevice::bytesAvailable();
+}
- buffer = new char[BUFFER_SIZE];
+AudioTest::AudioTest()
+ : m_pullTimer(new QTimer(this))
+ , m_modeButton(0)
+ , m_suspendResumeButton(0)
+ , m_deviceBox(0)
+ , m_generator(0)
+ , m_audioOutput(0)
+ , m_output(0)
+ , m_buffer(BufferSize, 0)
+{
+ initializeWindow();
+ initializeAudio();
+}
- gen = new Generator(this);
+void AudioTest::initializeWindow()
+{
+ QScopedPointer<QWidget> window(new QWidget);
+ QScopedPointer<QVBoxLayout> layout(new QVBoxLayout);
- pullMode = true;
+ m_deviceBox = new QComboBox(this);
+ foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput))
+ m_deviceBox->addItem(deviceInfo.deviceName(), qVariantFromValue(deviceInfo));
+ connect(m_deviceBox,SIGNAL(activated(int)),SLOT(deviceChanged(int)));
+ layout->addWidget(m_deviceBox);
+
+ m_modeButton = new QPushButton(this);
+ m_modeButton->setText(PushModeLabel);
+ connect(m_modeButton, SIGNAL(clicked()), SLOT(toggleMode()));
+ layout->addWidget(m_modeButton);
+
+ m_suspendResumeButton = new QPushButton(this);
+ m_suspendResumeButton->setText(SuspendLabel);
+ connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume()));
+ layout->addWidget(m_suspendResumeButton);
+
+ window->setLayout(layout.data());
+ layout.take(); // ownership transferred
+
+ setCentralWidget(window.data());
+ QWidget *const windowPtr = window.take(); // ownership transferred
+ windowPtr->show();
+}
- timer = new QTimer(this);
- connect(timer,SIGNAL(timeout()),SLOT(writeMore()));
+void AudioTest::initializeAudio()
+{
+ connect(m_pullTimer, SIGNAL(timeout()), SLOT(pullTimerExpired()));
- gen->start();
+ m_pullMode = true;
- settings.setFrequency(SYSTEM_FREQ);
- settings.setChannels(1);
- settings.setSampleSize(16);
- settings.setCodec("audio/pcm");
- settings.setByteOrder(QAudioFormat::LittleEndian);
- settings.setSampleType(QAudioFormat::SignedInt);
+ m_format.setFrequency(DataFrequencyHz);
+ m_format.setChannels(1);
+ m_format.setSampleSize(16);
+ m_format.setCodec("audio/pcm");
+ m_format.setByteOrder(QAudioFormat::LittleEndian);
+ m_format.setSampleType(QAudioFormat::SignedInt);
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
- if (!info.isFormatSupported(settings)) {
- qWarning()<<"default format not supported try to use nearest";
- settings = info.nearestFormat(settings);
+ if (!info.isFormatSupported(m_format)) {
+ qWarning() << "Default format not supported - trying to use nearest";
+ m_format = info.nearestFormat(m_format);
}
- if(settings.sampleSize() != 16) {
- qWarning()<<"audio device doesn't support 16 bit samples, example cannot run";
- button->setDisabled(true);
- button2->setDisabled(true);
- audioOutput = 0;
- return;
- }
+ m_generator = new Generator(m_format, DurationSeconds*1000000, ToneFrequencyHz, this);
- audioOutput = new QAudioOutput(settings,this);
- connect(audioOutput,SIGNAL(notify()),SLOT(status()));
- connect(audioOutput,SIGNAL(stateChanged(QAudio::State)),SLOT(state(QAudio::State)));
+ createAudioOutput();
+}
- audioOutput->start(gen);
+void AudioTest::createAudioOutput()
+{
+ delete m_audioOutput;
+ m_audioOutput = 0;
+ m_audioOutput = new QAudioOutput(m_format, this);
+ connect(m_audioOutput, SIGNAL(notify()), SLOT(notified()));
+ connect(m_audioOutput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State)));
+ m_generator->start();
+ m_audioOutput->start(m_generator);
}
AudioTest::~AudioTest()
{
- delete [] buffer;
+
}
-void AudioTest::deviceChanged(int idx)
+void AudioTest::deviceChanged(int index)
{
- timer->stop();
- gen->stop();
- audioOutput->stop();
- audioOutput->disconnect(this);
- delete audioOutput;
-
- device = deviceBox->itemData(idx).value<QAudioDeviceInfo>();
- audioOutput = new QAudioOutput(device,settings,this);
- connect(audioOutput,SIGNAL(notify()),SLOT(status()));
- connect(audioOutput,SIGNAL(stateChanged(QAudio::State)),SLOT(state(QAudio::State)));
- gen->start();
- audioOutput->start(gen);
+ m_pullTimer->stop();
+ m_generator->stop();
+ m_audioOutput->stop();
+ m_audioOutput->disconnect(this);
+ m_device = m_deviceBox->itemData(index).value<QAudioDeviceInfo>();
+ createAudioOutput();
}
-void AudioTest::status()
+void AudioTest::notified()
{
- qWarning() << "byteFree = " << audioOutput->bytesFree() << " bytes, elapsedUSecs = " << audioOutput->elapsedUSecs() << ", processedUSecs = " << audioOutput->processedUSecs();
+ qWarning() << "bytesFree = " << m_audioOutput->bytesFree()
+ << ", " << "elapsedUSecs = " << m_audioOutput->elapsedUSecs()
+ << ", " << "processedUSecs = " << m_audioOutput->processedUSecs();
}
-void AudioTest::writeMore()
+void AudioTest::pullTimerExpired()
{
- if (!audioOutput)
- return;
-
- if (audioOutput->state() == QAudio::StoppedState)
- return;
-
- int l;
- int out;
-
- int chunks = audioOutput->bytesFree()/audioOutput->periodSize();
- while(chunks) {
- l = gen->read(buffer,audioOutput->periodSize());
- if (l > 0)
- out = output->write(buffer,l);
- if (l != audioOutput->periodSize())
- break;
- chunks--;
+ if (m_audioOutput && m_audioOutput->state() != QAudio::StoppedState) {
+ int chunks = m_audioOutput->bytesFree()/m_audioOutput->periodSize();
+ while (chunks) {
+ const qint64 len = m_generator->read(m_buffer.data(), m_audioOutput->periodSize());
+ if (len)
+ m_output->write(m_buffer.data(), len);
+ if (len != m_audioOutput->periodSize())
+ break;
+ --chunks;
+ }
}
}
-void AudioTest::toggle()
+void AudioTest::toggleMode()
{
- // Change between pull and push modes
-
- timer->stop();
- audioOutput->stop();
-
- if (pullMode) {
- button->setText("Click for Pull Mode");
- output = audioOutput->start();
- pullMode = false;
- timer->start(20);
+ m_pullTimer->stop();
+ m_audioOutput->stop();
+
+ if (m_pullMode) {
+ m_modeButton->setText(PullModeLabel);
+ m_output = m_audioOutput->start();
+ m_pullMode = false;
+ m_pullTimer->start(20);
} else {
- button->setText("Click for Push Mode");
- pullMode = true;
- audioOutput->start(gen);
+ m_modeButton->setText(PushModeLabel);
+ m_pullMode = true;
+ m_audioOutput->start(m_generator);
}
+
+ m_suspendResumeButton->setText(SuspendLabel);
}
-void AudioTest::togglePlay()
+void AudioTest::toggleSuspendResume()
{
- // toggle suspend/resume
- if (audioOutput->state() == QAudio::SuspendedState) {
+ if (m_audioOutput->state() == QAudio::SuspendedState) {
qWarning() << "status: Suspended, resume()";
- audioOutput->resume();
- button2->setText("Click To Suspend");
- } else if (audioOutput->state() == QAudio::ActiveState) {
+ m_audioOutput->resume();
+ m_suspendResumeButton->setText(SuspendLabel);
+ } else if (m_audioOutput->state() == QAudio::ActiveState) {
qWarning() << "status: Active, suspend()";
- audioOutput->suspend();
- button2->setText("Click To Resume");
- } else if (audioOutput->state() == QAudio::StoppedState) {
+ m_audioOutput->suspend();
+ m_suspendResumeButton->setText(ResumeLabel);
+ } else if (m_audioOutput->state() == QAudio::StoppedState) {
qWarning() << "status: Stopped, resume()";
- audioOutput->resume();
- button2->setText("Click To Suspend");
- } else if (audioOutput->state() == QAudio::IdleState) {
+ m_audioOutput->resume();
+ m_suspendResumeButton->setText(SuspendLabel);
+ } else if (m_audioOutput->state() == QAudio::IdleState) {
qWarning() << "status: IdleState";
}
}
-void AudioTest::state(QAudio::State state)
+void AudioTest::stateChanged(QAudio::State state)
{
- qWarning() << " state=" << state;
+ qWarning() << "state = " << state;
}
diff --git a/examples/multimedia/audiooutput/audiooutput.h b/examples/multimedia/audiooutput/audiooutput.h
index 372cf78..889482b 100644
--- a/examples/multimedia/audiooutput/audiooutput.h
+++ b/examples/multimedia/audiooutput/audiooutput.h
@@ -41,14 +41,13 @@
#include <math.h>
-#define BUFFER_SIZE 32768
-
#include <QObject>
#include <QMainWindow>
#include <QIODevice>
#include <QTimer>
#include <QPushButton>
#include <QComboBox>
+#include <QByteArray>
#include <QAudioOutput>
@@ -56,26 +55,22 @@ class Generator : public QIODevice
{
Q_OBJECT
public:
- Generator(QObject *parent);
+ Generator(const QAudioFormat &format, qint64 durationUs, int frequency, QObject *parent);
~Generator();
void start();
void stop();
- char *t;
- int len;
- int pos;
- int total;
- char *buffer;
- bool finished;
- int chunk_size;
-
qint64 readData(char *data, qint64 maxlen);
qint64 writeData(const char *data, qint64 len);
+ qint64 bytesAvailable() const;
private:
- int putShort(char *t, unsigned int value);
- int fillData(char *start, int frequency, int seconds);
+ void generateData(const QAudioFormat &format, qint64 durationUs, int frequency);
+
+private:
+ qint64 m_pos;
+ QByteArray m_buffer;
};
class AudioTest : public QMainWindow
@@ -85,26 +80,39 @@ public:
AudioTest();
~AudioTest();
- QAudioDeviceInfo device;
- Generator* gen;
- QAudioOutput* audioOutput;
- QIODevice* output;
- QTimer* timer;
- QAudioFormat settings;
+private:
+ void initializeWindow();
+ void initializeAudio();
+ void createAudioOutput();
+
+private:
+ QTimer* m_pullTimer;
+
+ // Owned by layout
+ QPushButton* m_modeButton;
+ QPushButton* m_suspendResumeButton;
+ QComboBox* m_deviceBox;
+
+ QAudioDeviceInfo m_device;
+ Generator* m_generator;
+ QAudioOutput* m_audioOutput;
+ QIODevice* m_output; // not owned
+ QAudioFormat m_format;
- bool pullMode;
- char* buffer;
+ bool m_pullMode;
+ QByteArray m_buffer;
- QPushButton* button;
- QPushButton* button2;
- QComboBox* deviceBox;
+ static const QString PushModeLabel;
+ static const QString PullModeLabel;
+ static const QString SuspendLabel;
+ static const QString ResumeLabel;
private slots:
- void status();
- void writeMore();
- void toggle();
- void togglePlay();
- void state(QAudio::State s);
- void deviceChanged(int idx);
+ void notified();
+ void pullTimerExpired();
+ void toggleMode();
+ void toggleSuspendResume();
+ void stateChanged(QAudio::State state);
+ void deviceChanged(int index);
};