audioinput.cpp
Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
00004 ** All rights reserved.
00005 ** Contact: Nokia Corporation (qt-info@nokia.com)
00006 **
00007 ** This file is part of the examples of the Qt Toolkit.
00008 **
00009 ** $QT_BEGIN_LICENSE:LGPL$
00010 ** Commercial Usage
00011 ** Licensees holding valid Qt Commercial licenses may use this file in
00012 ** accordance with the Qt Commercial License Agreement provided with the
00013 ** Software or, alternatively, in accordance with the terms contained in
00014 ** a written agreement between you and Nokia.
00015 **
00016 ** GNU Lesser General Public License Usage
00017 ** Alternatively, this file may be used under the terms of the GNU Lesser
00018 ** General Public License version 2.1 as published by the Free Software
00019 ** Foundation and appearing in the file LICENSE.LGPL included in the
00020 ** packaging of this file.  Please review the following information to
00021 ** ensure the GNU Lesser General Public License version 2.1 requirements
00022 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
00023 **
00024 ** In addition, as a special exception, Nokia gives you certain additional
00025 ** rights.  These rights are described in the Nokia Qt LGPL Exception
00026 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
00027 **
00028 ** GNU General Public License Usage
00029 ** Alternatively, this file may be used under the terms of the GNU
00030 ** General Public License version 3.0 as published by the Free Software
00031 ** Foundation and appearing in the file LICENSE.GPL included in the
00032 ** packaging of this file.  Please review the following information to
00033 ** ensure the GNU General Public License version 3.0 requirements will be
00034 ** met: http://www.gnu.org/copyleft/gpl.html.
00035 **
00036 ** If you have questions regarding the use of this file, please contact
00037 ** Nokia at qt-info@nokia.com.
00038 ** $QT_END_LICENSE$
00039 **
00040 ****************************************************************************/
00041 
00042 #include <stdlib.h>
00043 #include <math.h>
00044 
00045 #include <QDebug>
00046 #include <QPainter>
00047 #include <QPalette>
00048 #include <QVBoxLayout>
00049 
00050 #include <QAudioDeviceInfo>
00051 #include <QAudioInput>
00052 #include "audioinput.h"
00053 #include "wavefile.h"
00054 
00055 ATRASR_CLIENT _atrasrClient;
00056 int _epdPort = 0;
00057 
00058 static int _logCounter = 0;
00059 static int _speakCount = 0;
00060 static int _filenum = 1;
00061 
00062 static int _epdOnFrameNo = -1;
00063 static int _epdOffFrameNo = -1;
00064 
00065 #define BUFFER_SIZE 4096
00066 
00067 AudioInfo::AudioInfo(QObject* parent, QAudioInput* device, SoundServer *server)
00068     :QIODevice( parent )
00069 {
00070     input = device;
00071     m_server = server;
00072 
00073     m_bRec = false;
00074     m_file = NULL;
00075 
00076     m_bEpdOn = true; //(_atrasrClient.socket != NULL);
00077     m_bEpdEnabled = m_bEpdOn;
00078     if (_atrasrClient.socket != NULL){
00079         connect(_atrasrClient.socket, SIGNAL(readyRead()), this, SLOT(epdRead()));
00080     }
00081     connect(server, SIGNAL(onCmd(QString)), this, SLOT(onCmd(QString)));
00082     connect(server, SIGNAL(clientConnected(QHostAddress)), this, SLOT(onClientConnected(QHostAddress)));
00083 }
00084 
00085 AudioInfo::~AudioInfo()
00086 {
00087 }
00088 
00089 QList<AudioInfo::Level> AudioInfo::getLevels()
00090 {
00091     QList<Level> levels = m_levels;
00092     m_levels.clear();
00093     return levels;
00094 }
00095 
00096 bool AudioInfo::epdEnabled() const
00097 {
00098     return m_bEpdEnabled;
00099 }
00100 
00101 void AudioInfo::setEpdEnabled(bool bEnabled)
00102 {
00103     m_bEpdEnabled = bEnabled;
00104     m_bEpdOn = bEnabled;
00105 
00106     if ( bEnabled ) {
00107         m_server->SendEpdOn();
00108     } else {
00109         m_server->SendEpdOff();
00110         recstop(false);
00111     }
00112 }
00113 
00114 void AudioInfo::start()
00115 {
00116     open(QIODevice::WriteOnly);
00117 }
00118 
00119 void AudioInfo::stop()
00120 {
00121     recstop();
00122     close();
00123 }
00124 
00125 qint64 AudioInfo::readData(char *data, qint64 maxlen)
00126 {
00127     Q_UNUSED(data)
00128     Q_UNUSED(maxlen)
00129 
00130     return 0;
00131 }
00132 
00133 qint64 AudioInfo::writeData(const char *data, qint64 len)
00134 {
00135     if (_atrasrClient.socket == NULL){
00136         processWave(data, len);
00137     }
00138     else{
00139         AtrasrSendDATA(&_atrasrClient, data, len);
00140     }
00141 
00142     return len;
00143 }
00144 
00145 void AudioInfo::processWave(const void *data, qint64 len)
00146 {
00147     if (m_bRec){
00148         if (m_file != NULL){
00149             m_file->write((const char*)data,len);
00150         }
00151         m_server->SendData(data,len);
00152         m_sampleSize += len;
00153     }
00154 
00155     // sample format is S16LE, only!
00156     int min = 0;
00157     int max = 0;
00158 
00159     int samples = len/2; // 2 bytes per sample
00160     qint16* s = (qint16*)data;
00161     for(int i = 0; i < samples; i++) {
00162         qint16 sample = *s;
00163         s++;
00164         if(sample < min) min = sample;
00165         if(sample > max) max = sample;
00166 
00167         if (i > 0 && i % 480 == 0){
00168             m_levels.append(Level(min,max,m_bRec,m_bEpdOn));
00169             min = 0;
00170             max = 0;
00171         }
00172     }
00173     m_levels.append(Level(min,max,m_bRec,m_bEpdOn));
00174 
00175     emit update();
00176 }
00177 
00178 void AudioInfo::epdRead()
00179 {
00180     long frameType;
00181     int frameIndex;
00182     unsigned char *pData;
00183     static unsigned char recvData[ATRASR_RECV_BUF_FRAME_COUNT * ATRASR_FRAME_DATA_SIZE];
00184     int recvSize = 0;
00185 
00186     int frameCount = AtrasrReceiveFrame( &_atrasrClient );
00187 
00188     for ( frameIndex = 0; frameIndex < frameCount; frameIndex++ )
00189     {
00190         pData = AtrasrParseFrame( &_atrasrClient, frameIndex, &frameType );
00191 
00192         if ( frameType == ATRASR_TOF ) {
00193             qDebug() << "NICTASR : TOF frame received.";
00194 
00195             if ( m_bEpdOn ) {
00196                 m_server->SendEpdOn();
00197             } else {
00198                 m_server->SendEpdOff();
00199             }
00200         }
00201         else if ( frameType == ATRASR_DATA ) {
00202             memcpy( recvData + recvSize, pData, ATRASR_FRAME_DATA_SIZE );
00203             recvSize += ATRASR_FRAME_DATA_SIZE;
00204 
00205             if(_logCounter % 80 == 0){
00206                 _logCounter = 0;
00207                 qDebug() << "send : " << _atrasrClient.sendFrameCount << "recv : " << _atrasrClient.recvFrameCount << "Off : " << _epdOffFrameNo << "On : " << _epdOnFrameNo;
00208             }
00209             _logCounter++;
00210 
00211             /* EPDのON切り替え */
00212             if (_epdOnFrameNo >= 0 && _atrasrClient.sendFrameCount >= _epdOnFrameNo){
00213                 qDebug() << "EPD ON.";
00214                 _speakCount--;
00215                 if(_speakCount<=0){
00216                     _speakCount=0;
00217                     m_bEpdOn = true;
00218                     emit validateRecButton(true);
00219                     m_server->SendEpdOn();
00220                 }
00221                 _epdOnFrameNo = -1;
00222             }
00223 
00224             if (_epdOffFrameNo >= 0 &&_atrasrClient.sendFrameCount >= _epdOffFrameNo ) {
00225                 qDebug() << "EPD OFF.";
00226                 m_bEpdOn = false;
00227                 m_server->SendEpdOff();
00228                 _epdOffFrameNo = -1;
00229             }
00230         }
00231         else if ( frameType == ATRASR_EOF ) {
00232             qDebug() << "NICTASR : EOF frame received.";
00233             qDebug() << "NICTASR : " << _atrasrClient.sendFrameCount << " frames sent. " << _atrasrClient.recvFrameCount << " frames received";
00234         }
00235         else if ( frameType == ATRASR_START ) {
00236             if ( recvSize > 0 ) {
00237                 qDebug() << "RECVSIZE : " << recvSize;
00238                 processWave( recvData, recvSize );
00239                 recvSize = 0;
00240             }
00241 
00242             qDebug() << "NICTASR : START frame received. (" << _atrasrClient.sendFrameCount << " sent, " << _atrasrClient.recvFrameCount << " received)";
00243 
00244             if ( m_bEpdOn ){
00245                 recstart();
00246             }
00247         }
00248         else if ( frameType == ATRASR_END || frameType == ATRASR_CANCEL ) {
00249             if ( recvSize > 0 ) {
00250                 processWave( recvData, recvSize );
00251                 recvSize = 0;
00252             }
00253 
00254             qDebug() << "NICTASR : " << (( frameType == ATRASR_END ) ? "END" : "CANCEL") << " frame received. ";
00255 
00256             if ( m_bEpdOn ){
00257                 recstop( frameType == ATRASR_END );
00258             }
00259         }
00260         else {
00261             qDebug() << "NICTASR : Unknown frame type : " << frameType;
00262         }
00263     }
00264 
00265     if ( recvSize > 0 ) {
00266         processWave( recvData, recvSize );
00267     }
00268 }
00269 
00270 void AudioInfo::onCmd(const QString &cmd)
00271 {
00272     qDebug() << "Command Received - " << cmd;
00273 
00274     if (cmd.isEmpty()){
00275         return;
00276     }
00277 
00278     // cancel recording.
00279     if (m_bRec){
00280         recstop(false);
00281     }
00282 
00283     // Epd ON/OFF
00284     if ( cmd == "epdon" || cmd == "epdoff" ){
00285         /* ATRASRと繋いでいるときだけ有効 */
00286         if ( _atrasrClient.socket && m_bEpdEnabled ){
00287             /* 音声採取時のフレーム番号(+オフセット)を覚えておき、それに対してEPDのONを行う。 */
00288             const int OFFSET = 80;
00289             if ( cmd == "epdon" ){
00290                 _epdOnFrameNo = _atrasrClient.sendFrameCount;
00291                 _epdOnFrameNo += OFFSET;
00292             }
00293             /* OFFはすぐに行う。前回のONフレームを待っている状態なら取り消す(0FF優先)。 */
00294             else{
00295                 _epdOffFrameNo = _atrasrClient.sendFrameCount;
00296                 _speakCount++;
00297                 emit validateRecButton(false);
00298                 m_bEpdOn = false;
00299             }
00300 
00301             qDebug() << "Send frame count:" << _atrasrClient.sendFrameCount << " Recv frame count: " << _atrasrClient.recvFrameCount;
00302         }
00303         else{
00304             qDebug() << "Invalid command in non-auto-detect mode : " << cmd;
00305         }
00306     }
00307     else{
00308         qDebug() << "Unknown command - " << cmd;
00309     }
00310 }
00311 
00312 void AudioInfo::onClientConnected(const QHostAddress &addr)
00313 {
00314     if (_epdPort == 0 || _atrasrClient.socket != NULL){
00315         return;
00316     }
00317 
00318     if ( AtrasrConnect( &_atrasrClient, addr.toString().toLatin1(), _epdPort ) != -1 ){
00319         AtrasrSendTOF( &_atrasrClient );
00320         AtrasrSendSTARTPU( &_atrasrClient );
00321         connect(_atrasrClient.socket, SIGNAL(readyRead()), this, SLOT(epdRead()));
00322         connect(_atrasrClient.socket, SIGNAL(disconnected()), this, SLOT(epdDisconnected()));
00323     }
00324 }
00325 
00326 void AudioInfo::epdDisconnected()
00327 {
00328     _atrasrClient.socket->deleteLater();
00329     _atrasrClient.socket = NULL;
00330 
00331     _speakCount = 0;
00332     _epdOnFrameNo = -1;
00333     if (m_bEpdEnabled){
00334         m_bEpdOn = true;
00335     }
00336 
00337     recstop(false);
00338 }
00339 
00340 void AudioInfo::recstart()
00341 {
00342     m_bRec = true;
00343 
00344     QString fileSufix;
00345     if (!m_filename.isEmpty()){
00346         fileSufix.sprintf(".%04d", _filenum++);
00347         m_file = WaveFile::createHeader(m_filename + fileSufix);
00348     }
00349     m_sampleSize = 0;
00350 
00351     m_server->SendStart();
00352 }
00353 
00354 void AudioInfo::recstop(bool bEnd)
00355 {
00356     if (m_bRec){
00357         m_bRec = false;
00358         if (m_file != NULL){
00359             WaveFile::fillHeader(m_file, m_sampleSize);
00360             QString filename = m_file->fileName();
00361             m_file->close();
00362             delete m_file;
00363             m_file = NULL;
00364             QFile::remove(filename+".wav");
00365             QFile::rename(filename, filename+".wav");
00366         }
00367         if (bEnd){
00368             m_server->SendEnd();
00369         }
00370         else{
00371             m_server->SendEnd();
00372             //m_server->SendCancel();
00373         }
00374     }
00375 }
00376 
00377 QString AudioInfo::m_filename;
00378 
00379 void AudioInfo::setFileName(const QString &filename)
00380 {
00381     m_filename = filename;
00382 }
00383 
00384 int RenderArea::STEP = 150;
00385 
00386 RenderArea::RenderArea(QWidget *parent)
00387     : QWidget(parent)
00388 {
00389     //setBackgroundRole(QPalette::Base);
00390     //setAutoFillBackground(true);
00391 
00392     setMinimumHeight(30);
00393     setMinimumWidth(50);
00394 
00395     for(int i = 0; i < STEP; i++){
00396         m_levels.enqueue(AudioInfo::Level());
00397     }
00398 }
00399 
00400 void RenderArea::paintEvent(QPaintEvent * /* event */)
00401 {
00402     QPainter painter(this);
00403 
00404     int centerY = painter.viewport().center().y();
00405 
00406     for(int i = 0; i < STEP; i++){
00407         AudioInfo::Level level = m_levels.at(i);
00408 
00409         QRect rect(
00410             (double)painter.viewport().left() + i*(double)painter.viewport().width()/STEP,
00411             painter.viewport().top(),
00412             (double)painter.viewport().width()/STEP,
00413             painter.viewport().height()
00414         );
00415         QColor color = !level.epdOn ? Qt::lightGray :(level.recording ? Qt::blue : Qt::black);
00416         painter.setPen(color);
00417         painter.setBrush(QBrush(color, Qt::SolidPattern));
00418         painter.drawRect(rect);
00419 
00420         rect.setTop( centerY - level.max*painter.viewport().height()/2 );
00421         rect.setHeight( (level.max-level.min)*painter.viewport().height()/2);
00422 
00423         color = level.recording ? Qt::yellow : QColor(127, 255, 255);
00424         painter.setPen(color);
00425         painter.setBrush(QBrush(color, Qt::SolidPattern));
00426         painter.drawRect(rect);
00427     }
00428 }
00429 
00430 void RenderArea::setLevel(const QList<AudioInfo::Level> &levels)
00431 {
00432     m_levels.append(levels);
00433     while (m_levels.count() > STEP){
00434         m_levels.dequeue();
00435     }
00436     repaint();
00437 }
00438 
00439 
00440 SoundServerApp::SoundServerApp(SoundServer *_server)
00441     : server(_server)
00442 {
00443     QWidget *window = new QWidget;
00444     QVBoxLayout* layout = new QVBoxLayout;
00445 
00446     canvas = new RenderArea;
00447     layout->addWidget(canvas);
00448 
00449     recButton = new QPushButton(this);
00450     recButton->setText(tr("REC"));
00451     recButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
00452     layout->addWidget(recButton);
00453 
00454     deviceBox = new QComboBox(this);
00455     QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
00456     for(int i = 0; i < devices.size(); ++i) {
00457         QString deviceName = devices.at(i).deviceName();
00458         if (deviceName.length() > 20) {
00459             deviceName = deviceName.left(19).append("...");
00460         }
00461         deviceBox->addItem(deviceName, qVariantFromValue(devices.at(i)));
00462     }
00463     connect(deviceBox,SIGNAL(activated(int)),SLOT(deviceChanged(int)));
00464     layout->addWidget(deviceBox);
00465 
00466     window->setLayout(layout);
00467     setCentralWidget(window);
00468     window->show();
00469 
00470     buffer = new char[BUFFER_SIZE];
00471 
00472     pullMode = true;
00473 
00474     // AudioInfo class only supports mono S16LE samples!
00475     format.setSampleRate(WaveFile::SAMPLING_RATE);
00476     format.setChannelCount(1);
00477     format.setSampleSize(WaveFile::SAMPLE_BYTE*8);
00478     format.setSampleType(QAudioFormat::SignedInt);
00479     format.setByteOrder(QAudioFormat::LittleEndian);
00480     format.setCodec("audio/pcm");
00481 
00482     audioInput = new QAudioInput(format,this);
00483     connect(audioInput,SIGNAL(notify()),SLOT(status()));
00484     connect(audioInput,SIGNAL(stateChanged(QAudio::State)),SLOT(state(QAudio::State)));
00485     audioinfo  = new AudioInfo(this,audioInput,server);
00486     connect(audioinfo,SIGNAL(update()),SLOT(refreshDisplay()));
00487     connect(audioinfo,SIGNAL(validateRecButton(bool)),this,SLOT(epdSpeechChanged(bool)));
00488     audioinfo->start();
00489     audioInput->start(audioinfo);
00490 
00491     if (!devices.empty()){
00492         deviceChanged(0);
00493     }
00494 
00495     //if (_atrasrClient.socket != NULL){
00496     if (_epdPort > 0){
00497         recButton->setCheckable(true);
00498         recButton->setChecked(true);
00499         epdEnableChanged(true);
00500         connect(recButton,SIGNAL(toggled(bool)),this,SLOT(epdEnableChanged(bool)));
00501     }
00502     else{
00503         connect(recButton,SIGNAL(pressed()),audioinfo,SLOT(recstart()));
00504         connect(recButton,SIGNAL(released()),audioinfo,SLOT(recstop()));
00505     }
00506 }
00507 
00508 SoundServerApp::~SoundServerApp() {}
00509 
00510 void SoundServerApp::status()
00511 {
00512     //qWarning()<<"bytesReady = "<<audioInput->bytesReady()<<" bytes, elapsedUSecs = "<FFFFFFFFF<audioInput->elapsedUSecs()<<", processedUSecs = "<<audioInput->processedUSecs();
00513 }
00514 
00515 void SoundServerApp::readMore()
00516 {
00517     if(!audioInput)
00518         return;
00519     qint64 len = audioInput->bytesReady();
00520     if(len > 4096)
00521         len = 4096;
00522     qint64 l = input->read(buffer,len);
00523     if(l > 0) {
00524         audioinfo->write(buffer,l);
00525     }
00526 }
00527 
00528 void SoundServerApp::toggleMode()
00529 {
00530     // Change bewteen pull and push modes
00531     audioInput->stop();
00532 
00533     if (pullMode) {
00534         button->setText(tr("Click for Pull Mode"));
00535         input = audioInput->start();
00536         connect(input,SIGNAL(readyRead()),SLOT(readMore()));
00537         pullMode = false;
00538     } else {
00539         button->setText(tr("Click for Push Mode"));
00540         pullMode = true;
00541         audioInput->start(audioinfo);
00542     }
00543 }
00544 
00545 void SoundServerApp::toggleSuspend()
00546 {
00547     // toggle suspend/resume
00548     if(audioInput->state() == QAudio::SuspendedState) {
00549         qWarning()<<"status: Suspended, resume()";
00550         audioInput->resume();
00551         button2->setText("Click To Suspend");
00552     } else if (audioInput->state() == QAudio::ActiveState) {
00553         qWarning()<<"status: Active, suspend()";
00554         audioInput->suspend();
00555         button2->setText("Click To Resume");
00556     } else if (audioInput->state() == QAudio::StoppedState) {
00557         qWarning()<<"status: Stopped, resume()";
00558         audioInput->resume();
00559         button2->setText("Click To Suspend");
00560     } else if (audioInput->state() == QAudio::IdleState) {
00561         qWarning()<<"status: IdleState";
00562     }
00563 }
00564 
00565 void SoundServerApp::state(QAudio::State state)
00566 {
00567     qWarning()<<" state="<<state;
00568 }
00569 
00570 void SoundServerApp::refreshDisplay()
00571 {
00572     canvas->setLevel(audioinfo->getLevels());
00573     canvas->repaint();
00574 }
00575 
00576 void SoundServerApp::deviceChanged(int idx)
00577 {
00578     audioinfo->stop();
00579     audioInput->stop();
00580     audioInput->disconnect(this);
00581     delete audioInput;
00582 
00583     device = deviceBox->itemData(idx).value<QAudioDeviceInfo>();
00584     audioInput = new QAudioInput(device, format, this);
00585     connect(audioInput,SIGNAL(notify()),SLOT(status()));
00586     connect(audioInput,SIGNAL(stateChanged(QAudio::State)),SLOT(state(QAudio::State)));
00587     audioinfo->start();
00588     audioInput->start(audioinfo);
00589 }
00590 
00591 void SoundServerApp::epdEnableChanged(bool bEnabled)
00592 {
00593     recButton->setText(bEnabled ? "Speech Detection ON" : "Speech Detection OFF");
00594     audioinfo->setEpdEnabled(bEnabled);
00595 }
00596 
00597 void SoundServerApp::epdSpeechChanged(bool bEnabled)
00598 {
00599     recButton->setEnabled(bEnabled);
00600 }
00601 
00602 void SoundServerApp::recstart()
00603 {
00604     audioinfo->recstart();
00605 }


rospeex_audiomonitor
Author(s): Komei Sugiura
autogenerated on Thu Jun 6 2019 18:53:06