source: trunk/examples/multimedia/audioinput/audioinput.cpp@ 769

Last change on this file since 769 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 11.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the examples of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <stdlib.h>
43#include <math.h>
44
45#include <QDebug>
46#include <QPainter>
47#include <QVBoxLayout>
48
49#include <QAudioDeviceInfo>
50#include <QAudioInput>
51
52#include <QtCore/qendian.h>
53
54#include "audioinput.h"
55
56const QString InputTest::PushModeLabel(tr("Enable push mode"));
57const QString InputTest::PullModeLabel(tr("Enable pull mode"));
58const QString InputTest::SuspendLabel(tr("Suspend recording"));
59const QString InputTest::ResumeLabel(tr("Resume recording"));
60
61const int BufferSize = 4096;
62
63AudioInfo::AudioInfo(const QAudioFormat &format, QObject *parent)
64 : QIODevice(parent)
65 , m_format(format)
66 , m_maxAmplitude(0)
67 , m_level(0.0)
68
69{
70 switch (m_format.sampleSize()) {
71 case 8:
72 switch (m_format.sampleType()) {
73 case QAudioFormat::UnSignedInt:
74 m_maxAmplitude = 255;
75 break;
76 case QAudioFormat::SignedInt:
77 m_maxAmplitude = 127;
78 break;
79 default: ;
80 }
81 break;
82 case 16:
83 switch (m_format.sampleType()) {
84 case QAudioFormat::UnSignedInt:
85 m_maxAmplitude = 65535;
86 break;
87 case QAudioFormat::SignedInt:
88 m_maxAmplitude = 32767;
89 break;
90 default: ;
91 }
92 break;
93 }
94}
95
96AudioInfo::~AudioInfo()
97{
98}
99
100void AudioInfo::start()
101{
102 open(QIODevice::WriteOnly);
103}
104
105void AudioInfo::stop()
106{
107 close();
108}
109
110qint64 AudioInfo::readData(char *data, qint64 maxlen)
111{
112 Q_UNUSED(data)
113 Q_UNUSED(maxlen)
114
115 return 0;
116}
117
118qint64 AudioInfo::writeData(const char *data, qint64 len)
119{
120 if (m_maxAmplitude) {
121 Q_ASSERT(m_format.sampleSize() % 8 == 0);
122 const int channelBytes = m_format.sampleSize() / 8;
123 const int sampleBytes = m_format.channels() * channelBytes;
124 Q_ASSERT(len % sampleBytes == 0);
125 const int numSamples = len / sampleBytes;
126
127 quint16 maxValue = 0;
128 const unsigned char *ptr = reinterpret_cast<const unsigned char *>(data);
129
130 for (int i = 0; i < numSamples; ++i) {
131 for(int j = 0; j < m_format.channels(); ++j) {
132 quint16 value = 0;
133
134 if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::UnSignedInt) {
135 value = *reinterpret_cast<const quint8*>(ptr);
136 } else if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::SignedInt) {
137 value = qAbs(*reinterpret_cast<const qint8*>(ptr));
138 } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::UnSignedInt) {
139 if (m_format.byteOrder() == QAudioFormat::LittleEndian)
140 value = qFromLittleEndian<quint16>(ptr);
141 else
142 value = qFromBigEndian<quint16>(ptr);
143 } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::SignedInt) {
144 if (m_format.byteOrder() == QAudioFormat::LittleEndian)
145 value = qAbs(qFromLittleEndian<qint16>(ptr));
146 else
147 value = qAbs(qFromBigEndian<qint16>(ptr));
148 }
149
150 maxValue = qMax(value, maxValue);
151 ptr += channelBytes;
152 }
153 }
154
155 maxValue = qMin(maxValue, m_maxAmplitude);
156 m_level = qreal(maxValue) / m_maxAmplitude;
157 }
158
159 emit update();
160 return len;
161}
162
163RenderArea::RenderArea(QWidget *parent)
164 : QWidget(parent)
165{
166 setBackgroundRole(QPalette::Base);
167 setAutoFillBackground(true);
168
169 m_level = 0;
170 setMinimumHeight(30);
171 setMinimumWidth(200);
172}
173
174void RenderArea::paintEvent(QPaintEvent * /* event */)
175{
176 QPainter painter(this);
177
178 painter.setPen(Qt::black);
179 painter.drawRect(QRect(painter.viewport().left()+10,
180 painter.viewport().top()+10,
181 painter.viewport().right()-20,
182 painter.viewport().bottom()-20));
183 if (m_level == 0.0)
184 return;
185
186 painter.setPen(Qt::red);
187
188 int pos = ((painter.viewport().right()-20)-(painter.viewport().left()+11))*m_level;
189 for (int i = 0; i < 10; ++i) {
190 int x1 = painter.viewport().left()+11;
191 int y1 = painter.viewport().top()+10+i;
192 int x2 = painter.viewport().left()+20+pos;
193 int y2 = painter.viewport().top()+10+i;
194 if (x2 < painter.viewport().left()+10)
195 x2 = painter.viewport().left()+10;
196
197 painter.drawLine(QPoint(x1, y1),QPoint(x2, y2));
198 }
199}
200
201void RenderArea::setLevel(qreal value)
202{
203 m_level = value;
204 repaint();
205}
206
207
208InputTest::InputTest()
209 : m_canvas(0)
210 , m_modeButton(0)
211 , m_suspendResumeButton(0)
212 , m_deviceBox(0)
213 , m_device(QAudioDeviceInfo::defaultInputDevice())
214 , m_audioInfo(0)
215 , m_audioInput(0)
216 , m_input(0)
217 , m_pullMode(false)
218 , m_buffer(BufferSize, 0)
219{
220 initializeWindow();
221 initializeAudio();
222}
223
224InputTest::~InputTest() {}
225
226void InputTest::initializeWindow()
227{
228 QScopedPointer<QWidget> window(new QWidget);
229 QScopedPointer<QVBoxLayout> layout(new QVBoxLayout);
230
231 m_canvas = new RenderArea(this);
232 layout->addWidget(m_canvas);
233
234 m_deviceBox = new QComboBox(this);
235 QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
236 for(int i = 0; i < devices.size(); ++i)
237 m_deviceBox->addItem(devices.at(i).deviceName(), qVariantFromValue(devices.at(i)));
238
239 connect(m_deviceBox, SIGNAL(activated(int)), SLOT(deviceChanged(int)));
240 layout->addWidget(m_deviceBox);
241
242 m_modeButton = new QPushButton(this);
243 m_modeButton->setText(PushModeLabel);
244 connect(m_modeButton, SIGNAL(clicked()), SLOT(toggleMode()));
245 layout->addWidget(m_modeButton);
246
247 m_suspendResumeButton = new QPushButton(this);
248 m_suspendResumeButton->setText(SuspendLabel);
249 connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspend()));
250 layout->addWidget(m_suspendResumeButton);
251
252 window->setLayout(layout.data());
253 layout.take(); // ownership transferred
254
255 setCentralWidget(window.data());
256 QWidget *const windowPtr = window.take(); // ownership transferred
257 windowPtr->show();
258}
259
260void InputTest::initializeAudio()
261{
262 m_pullMode = true;
263
264 m_format.setFrequency(8000);
265 m_format.setChannels(1);
266 m_format.setSampleSize(16);
267 m_format.setSampleType(QAudioFormat::SignedInt);
268 m_format.setByteOrder(QAudioFormat::LittleEndian);
269 m_format.setCodec("audio/pcm");
270
271 QAudioDeviceInfo info(QAudioDeviceInfo::defaultInputDevice());
272 if (!info.isFormatSupported(m_format)) {
273 qWarning() << "Default format not supported - trying to use nearest";
274 m_format = info.nearestFormat(m_format);
275 }
276
277 m_audioInfo = new AudioInfo(m_format, this);
278 connect(m_audioInfo, SIGNAL(update()), SLOT(refreshDisplay()));
279
280 createAudioInput();
281}
282
283void InputTest::createAudioInput()
284{
285 m_audioInput = new QAudioInput(m_device, m_format, this);
286 connect(m_audioInput, SIGNAL(notify()), SLOT(notified()));
287 connect(m_audioInput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State)));
288 m_audioInfo->start();
289 m_audioInput->start(m_audioInfo);
290}
291
292void InputTest::notified()
293{
294 qWarning() << "bytesReady = " << m_audioInput->bytesReady()
295 << ", " << "elapsedUSecs = " <<m_audioInput->elapsedUSecs()
296 << ", " << "processedUSecs = "<<m_audioInput->processedUSecs();
297}
298
299void InputTest::readMore()
300{
301 if(!m_audioInput)
302 return;
303 qint64 len = m_audioInput->bytesReady();
304 if(len > 4096)
305 len = 4096;
306 qint64 l = m_input->read(m_buffer.data(), len);
307 if(l > 0) {
308 m_audioInfo->write(m_buffer.constData(), l);
309 }
310}
311
312void InputTest::toggleMode()
313{
314 // Change bewteen pull and push modes
315 m_audioInput->stop();
316
317 if (m_pullMode) {
318 m_modeButton->setText(PullModeLabel);
319 m_input = m_audioInput->start();
320 connect(m_input, SIGNAL(readyRead()), SLOT(readMore()));
321 m_pullMode = false;
322 } else {
323 m_modeButton->setText(PushModeLabel);
324 m_pullMode = true;
325 m_audioInput->start(m_audioInfo);
326 }
327
328 m_suspendResumeButton->setText(SuspendLabel);
329}
330
331void InputTest::toggleSuspend()
332{
333 // toggle suspend/resume
334 if(m_audioInput->state() == QAudio::SuspendedState) {
335 qWarning() << "status: Suspended, resume()";
336 m_audioInput->resume();
337 m_suspendResumeButton->setText(SuspendLabel);
338 } else if (m_audioInput->state() == QAudio::ActiveState) {
339 qWarning() << "status: Active, suspend()";
340 m_audioInput->suspend();
341 m_suspendResumeButton->setText(ResumeLabel);
342 } else if (m_audioInput->state() == QAudio::StoppedState) {
343 qWarning() << "status: Stopped, resume()";
344 m_audioInput->resume();
345 m_suspendResumeButton->setText(SuspendLabel);
346 } else if (m_audioInput->state() == QAudio::IdleState) {
347 qWarning() << "status: IdleState";
348 }
349}
350
351void InputTest::stateChanged(QAudio::State state)
352{
353 qWarning() << "state = " << state;
354}
355
356void InputTest::refreshDisplay()
357{
358 m_canvas->setLevel(m_audioInfo->level());
359 m_canvas->repaint();
360}
361
362void InputTest::deviceChanged(int index)
363{
364 m_audioInfo->stop();
365 m_audioInput->stop();
366 m_audioInput->disconnect(this);
367 delete m_audioInput;
368
369 m_device = m_deviceBox->itemData(index).value<QAudioDeviceInfo>();
370 createAudioInput();
371}
Note: See TracBrowser for help on using the repository browser.