Unable to read microphone data and record to QFile ["SOLVED"]



  • Hi All,

    I have to objectives to be achieved:

    Firstly to record the microphone audio and store it in a QFile
    Secondly Play the recorded audio file using windows media player

    I have tried using the below code but when I execute my code, and start recording, the QAudioInput always returns byesRead() as 0 even if the state is QAudio::Active. Bacsically, in my case the QAudioInput fails to read the data from the desktop microphone. How do I solve this issue?

    @
    #ifndef MIC_DEMO_H
    #define MIC_DEMO_H

    #include <QtGui/QWidget>
    #include<QtMultimedia>
    #include "ui_mic_demo.h"

    class mikeDemoClass : public QWidget
    {
    Q_OBJECT

    public:
    mikeDemoClass(QWidget *parent = 0, Qt::WFlags flags = 0);
    ~mikeDemoClass();

    public slots:

    void startRecording();
    void browseFiles();
    void stopRecording();
    void handleAudioInputState(QAudio::State);
    void notified();

    private:
    Ui::mikeDemoWidget ui;
    QAudioInput *audioInput;
    QFile *recordFile;
    QTimer *testTimer;
    int audio_state;

    };

    #endif // MIC_DEMO_H

    //cpp file starts below

    #include <QIODevice>
    #include "mic_demo.h"

    mikeDemoClass::mikeDemoClass(QWidget *parent, Qt::WFlags flags)
    : QWidget(parent, flags)
    {
    ui.setupUi(this);
    audioInput = NULL;
    recordFile = NULL;
    audio_state = -1;

    connect(ui.browseButton,SIGNAL(clicked()),this,SLOT(browseFiles()));
    connect(ui.recordingButton,SIGNAL(clicked()), this,SLOT(startRecording()));
    }

    mikeDemoClass::~mikeDemoClass()
    {
    if(recordFile)
    {
    delete recordFile;
    recordFile = NULL;
    }
    }

    void mikeDemoClass::browseFiles()
    {
    QString FileName = QFileDialog::getSaveFileName(this, tr("Browse Files"), "D:/", tr("Media Files (*.wav)"));
    if(!FileName.isEmpty())
    {
    recordFile = new QFile(FileName);
    QTextDocument *textDoc = new QTextDocument(FileName);
    ui.textEdit->setDocument(textDoc);
    }

    }

    void mikeDemoClass::startRecording()
    {
    bool status = recordFile->open(QIODevice::WriteOnly);
    if(!status)
    {
    qDebug() <<"Error opening the file";
    }

    QString default_deviceName = "";
    QAudioFormat preferred_format;

    QList<QAudioDeviceInfo> device_list = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
    int count = device_list.count();

    if(device_list.empty())
    {
    qDebug() <<"The Audio Input Devices is empty";
    }
    else
    {
    foreach(QAudioDeviceInfo device_info, device_list)
    {
    QString device_name = device_info.deviceName();
    qDebug() << "device_name:" << device_name.toLatin1();
    }

    QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
    default_deviceName = info.deviceName();

    }

    QAudioFormat format;
    format.setSampleRate(8000);
    format.setChannels(1);
    format.setSampleSize(8);
    format.setCodec("audio/pcm");
    format.setByteOrder(QAudioFormat::LittleEndian);
    format.setSampleType(QAudioFormat::UnSignedInt);

    QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
    if(!info.isFormatSupported(format))
    {
    qDebug() <<"Default format not supported, try to use nearest format";
    format = info.nearestFormat(format);
    }

    audioInput = new QAudioInput(info, format, this);
    audioInput->setNotifyInterval(1000);
    connect(audioInput, SIGNAL(notify()), this, SLOT(notified()));
    connect(audioInput,SIGNAL(stateChanged(QAudio::State)),this, SLOT(handleAudioInputState(QAudio::State)));
    QTimer::singleShot(10000, this, SLOT(stopRecording()));

    qDebug() << "platform buffer size:" << audioInput->bufferSize();
    audioInput->start(recordFile);
    }

    void mikeDemoClass::stopRecording()
    {
    testTimer->stop();
    audioInput->stop();
    recordFile->close();
    delete audioInput;
    }

    void mikeDemoClass::handleAudioInputState(QAudio::State state)
    {
    qDebug() << "Audio State:" << state;

    audio_state = state;

    if(state == QAudio::StoppedState)
    {
    qDebug() << "Error State:" << audioInput->error();

    if(audioInput->error() != QAudio::NoError)
    {
    qDebug() << "QAudioInput error:" << audioInput->error();
    }
    }
    }

    void mikeDemoClass::notified()
    {
    if(audio_state == QAudio::ActiveState)
    {
    qDebug() << "Error State:" << audioInput->error();

    qDebug() << "platform buffer size after called QAudioInput start():" << audioInput->bufferSize();

    qDebug() << "bytesReady = " << audioInput->bytesReady()
    << ", " << "elapsedUSecs = " <<audioInput->elapsedUSecs()
    << ", " << "processedUSecs = "<<audioInput->processedUSecs();
    }

    }
    @

    If the above code is executed, the QAudioInput's method bytesReady() which is notified every second after recording starts shows 0.

    The output is as shown below:
    device_name: "Microphone (High Definition Aud"
    device_name: "default"
    codec: "audio/pcm" sampleRate : 11025 sampleSize: 8 channel Count: 1 sample type: 1 byteOrder: 1
    platform buffer size: 0
    Audio State: 0
    Error State: 0
    platform buffer size after called QAudioInput start(): 1600
    bytesReady = 0 , elapsedUSecs = 1003000 , processedUSecs = 1000000
    Error State: 0
    platform buffer size after called QAudioInput start(): 1600
    bytesReady = 0 , elapsedUSecs = 1999000 , processedUSecs = 2000000
    Error State: 0
    platform buffer size after called QAudioInput start(): 1600
    bytesReady = 0 , elapsedUSecs = 3004000 , processedUSecs = 3000000
    Error State: 0
    platform buffer size after called QAudioInput start(): 1600
    bytesReady = 0 , elapsedUSecs = 3999000 , processedUSecs = 4000000
    Error State: 0
    platform buffer size after called QAudioInput start(): 1600
    Audio State: 2
    Error State: 0

    It creates a .wav file in the specified location of size 80KB but windows media player does not play the file and throws an error saying unable to play the file type or codec not supported.


  • Moderators

    Hi,

    [quote]It creates a .wav file in the specified location of size 80KB but windows media player does not play the file and throws an error saying unable to play the file type or codec not supported.[/quote]QAudioInput produces raw PCM data. It doesn't encode the data into WAVE format, even if you tell it to write into a .wav file.

    In Qt 4, you need a 3rd party library to convert the raw data into WAVE format. In Qt 5, you can use "QAudioRecorder":http://qt-project.org/doc/qt-5/qaudiorecorder.html to produce .wav files.



  • @JKSH - thanks for the reply. But apart from the above problem, the other issue which i noticed is that QAudioInput's method bytesReady() always gives me 0 even when state is QAudio::ActiveState.I am not sure now if raw data is getting written into my raw file, even though the size shows as 60KB.

    When I start recording, the code doesn't throw any error and even state changes to Active but when i fetch bytesReady() it shows 0 always. What could be the possible reason?



  • @JKSH: Why does bytesReady() of QAudioInput always show 0 in my code even if the state is QAudio::ActiveState. I am continously tapping the microphone and trying to record the sound but bytesReady() is always 0.

    I guess this is the real issue in my case. I am not sure if there is anythg wrong with my system settings.

    The default audio input device info settings are as shown below:

    device_name: "Microphone (High Definition Aud"
    device_name: "default"
    supported codecs: "audio/pcm"
    codec: "audio/pcm" sampleRate : 11025 sampleSize: 8 channel Count: 1 sample type: 1 byteOrder: 1


  • Moderators

    [quote author="jeevan_reddy" date="1391076024"]Why does bytesReady() of QAudioInput always show 0 in my code even if the state is QAudio::ActiveState. I am continously tapping the microphone and trying to record the sound but bytesReady() is always 0.[/quote]Because bytesReady() does not tell you the total amount of data you have recorded. It tells you how much data is in the audio buffer.

    In your case, the data is transferred from the buffer into your file extremely quickly. The buffer is empty most of the time, so bytesReady() will return 0 most of the time.

    If you call bytesReady() every 1 millisecond, you might see a non-zero value occasionally. But most of the time, you will still see 0.

    [quote]I am not sure now if raw data is getting written into my raw file, even though the size shows as 60KB.[/quote]Your file is 60 kB, that means you have recorded 60 kB of raw audio :)

    If you download "Audacity":http://audacity.sourceforge.net/, you can use its "File" -> "Import" -> "Raw data..." feature to play your raw file. However, when you import, you must specify the audio format. Raw PCM files do not contain format information -- that is why Windows Media Player cannot understand it.



  • @JKSH - thanks a lot. Your explanation looks quite convincing. I'll try to call bytesReady() every 1ms and see if shows any value. I'll install audacity and try playing my raw files. So in my case when I import the raw file, should the audio format should be mentioned as "Raw Data"?
    I'll try this first thing tomorrow morning and let you know the result.
    I really appreciate your answers and keeping my fingers crossed in using Audacity.

    Btw I also tried using QAudioInput's other start() method which returns a pointer to QIODevice instead of the current start() which I have used. 
    

    The strange thing is that audio state never went to Active but was always in Idle state until the timer expired and QAudioInput's stop() was called. Basically it went to Idle state and then to stop. Is there any possible explanation for the behavior?

    I tried smethg like this:
    @QIODevice* input = QAudioInput->start();
    connect( input, SIGNAL(readyRead()), this, SLOT(readMore()));
    @

    but the slot was never called.



  • @JKSH - Your observations were bang on. I downloaded Audacity and played the raw files successfully.

    I also used the overloaded start() method of QAudioInput which returns pointer to QIODevice, even I got it working well. I believe its called "push" mode. The code which I posted above used "pull" mode.

    I'm glad that I got to learn smethg out of this post & especially interakting with u. Thank you once again :-)


  • Moderators

    That's great! I'm glad I could help :) You're welcome, and all the best with your project!

    P.S. Please edit your original message to add "[Solved]" to the title. This will let others know that your question has been answered.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.