My program is reading a configuration-file lines in a loop, and do a audio-recording for time = lines*100ms.
But for 5 same config-files I get 5 different length. (For 5sek recordings +-100ms)
I trying to change QThread::msleep(1500); or to declare QEventLoop and QTimer outside a loop, but there are no changes.
How can I get the recordings with right times?
Audio.cpp
// ************************************************************************************************
// Audio-Class
// ************************************************************************************************
#include "Audio.h"
#include "Measure.h"
#include <QAudioInput>
#include <QTimer>
// ************************************************************************************************
Audio::Audio()
{
QTimer *m_timer = new QTimer(this);
m_timer->setSingleShot(true);
AudioRecord();
}
// ************************************************************************************************
//Initialization and signal-slot connection
void Audio::AudioRecord()
{
//Set audio configuration
QAudioFormat format;
format.setSampleRate(44100);
format.setChannelCount(1);
format.setSampleSize(16);
format.setCodec("audio/PCM");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
//Wrong configuration detection
QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
if (!info.isFormatSupported(format))
{
qWarning() << "Default format not supported";
format = info.nearestFormat(format);
}
//Signal-slot connection to show actual Audio state or errors output
m_audio = new QAudioInput(format, this);
connect(m_audio, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChanged(QAudio::State)));
}
// ************************************************************************************************
//Start recording
//void Audio::StartRecording(QString rec_file_path)
void Audio::StartRecording(QString rec_file_path, quint32 record_time_msec)
{
m_file.setFileName(rec_file_path); //audio recording path format
m_file.open(QIODevice::WriteOnly); //audio access mode initialisation
writeHeader(); //writing header to convert PCM to *.wav (Step 1)
m_audio->start(&m_file); //start recording
//QTimer::singleShot((15000), this, SLOT(StopRecording()));
QTimer::singleShot((record_time_msec), this, SLOT(StopRecording()));
QCoreApplication::processEvents();
qDebug()<< m_audio->format();
//qDebug()<< m_file.open();
QAudioDeviceInfo::defaultInputDevice();
QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
//qDebug()<< m_audio->error();
//qDebug()<< m_audio->notifyInterval();
}
// ************************************************************************************************
//Write Header
// ************************************************************************************************
void Audio::writeHeader(){
quint64 data64 = 0;
quint32 data_Filesize_fill = 0;
quint32 data_lenght = 16;
quint16 data_PCM = 1;
quint16 data_Chanel = 1;
quint32 data_SamplRate = 44100;
quint32 data_Value = (44100 * 16 * 1)/8;
quint16 data_mono = (16 * 1)/8;
quint16 data_BPS = 16;
quint32 data_FileSize = 44;
m_file.write("RIFF",4);
m_file.write((char*)&data_Filesize_fill, 4);
m_file.write("WAVE",4);
m_file.write("fmt ",4); // "fmt " chunk size (always 16 for PCM)
m_file.write((char*)&data_lenght, 4);
m_file.write((char*)&data_PCM, 2);
m_file.write((char*)&data_Chanel, 2);
m_file.write((char*)&data_SamplRate, 4);
m_file.write((char*)&data_Value, 4); // bytes per second
m_file.write((char*)&data_mono, 2); // Block align
m_file.write((char*)&data_BPS, 2); // Bits per sample
m_file.write("data",4);
m_file.write((char*)&data_FileSize, 4);
m_file.flush();
}
// ************************************************************************************************
//Stop recording
void Audio::StopRecording()
{
m_audio->stop();
qDebug() << "stop";
writeHeaderFinal();
m_file.close();
qDebug() << "close";
}
// ************************************************************************************************
//Write Header
void Audio::writeHeaderFinal(){
quint32 data_Filesize_fill_after = m_file.size() - 8;
quint32 data_FileSize_after = m_file.size() - 44;
m_file.seek(4);
m_file.write((char*)&data_Filesize_fill_after, 4);
m_file.seek(40);
m_file.write((char*)&data_FileSize_after, 4);
}
// ************************************************************************************************
//Recording DEBUG output
void Audio::handleStateChanged(QAudio::State newState)
{
switch (newState)
{
case QAudio::StoppedState:
if (m_audio->error() != QAudio::NoError)
{
qDebug() << "Error audio recording!!";
} else
{
qDebug() << "Finished audio recording";
}
break;
case QAudio::ActiveState:
qDebug() << "Started audio recording";
break;
default:
break;
}
}
// ************************************************************************************************
Measure.cpp
// ************************************************************************************************
// Measure-Class
// ************************************************************************************************
//class initialisation
#include "Measure.h"
#include "Conf.h"
#include "Audio.h"
// ************************************************************************************************
Measure::Measure(Audio *audio)
{
//member variables init
m_audio = audio;
//UART-status debug
if (0 == connectSerial())
{
qDebug() << "Serial connection OK!\n";
}
else
{
qDebug() << "Serial connection Error!\n";
return;
}
auto info = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
foreach (auto i, info) qDebug() << i.deviceName();
//m_timer = new QTimer(this); double
//set serial connection
//connect(m_timer, SIGNAL(timeout()), this, SLOT(processMeas()),Qt::QueuedConnection);
measure_cnt = 0;
qDebug()<<"Starting programm";
}
// ************************************************************************************************
// Start measure
void Measure::start()
{
//QTimer *m_timer = new QTimer(this);
//m_timer->setSingleShot(true);
//m_timer->start(1000); 555
processMeas();
}
// ************************************************************************************************
// Serial connection initialization and signal-slot connection
uint32_t Measure::connectSerial(void)
{
//serial connection configuration
m_serial.setPortName("/dev/ttyACM0");
m_serial.setBaudRate(QSerialPort::Baud115200);
m_serial.setDataBits(QSerialPort::Data8);
m_serial.setParity(QSerialPort::NoParity);
m_serial.setStopBits(QSerialPort::OneStop);
m_serial.setFlowControl(QSerialPort::NoFlowControl);
if (!m_serial.open(QIODevice::ReadWrite))
return 1;
//einable serial connection
connect(&m_serial, SIGNAL(readyRead()), this, SLOT(readRequest()));
return 0;
}
// ************************************************************************************************
// State maschine
// ************************************************************************************************
void Measure::processMeas()
{
// Declaration ************************************************************
static uint32_t i = 0;
static uint32_t j = 0;
static uint8_t stm = 0;
static uint16_t m1 = 0;
static uint16_t m2 = 0;
static uint16_t m3 = 0;
static uint16_t m4 = 0;
static uint16_t var;
static QByteArray hextest;
// Read config files ***********************************************************************************
QDir directory("/home/nikitajarocky/workspace/QT/Software_2.0_QT/Config_files/");
QStringList config_files = directory.entryList(QStringList() << "*.config", QDir::Files);
config_files_cnt = config_files.count();
foreach(QString filename, config_files)
{
Conf *conf = new Conf(directory.absoluteFilePath(filename));
qDebug() << "Config file: " << filename << " is processed";
// Error message *************************
if(conf->getConf_lines().size() == 0)
{
qDebug()<<"Error conf file!!";
return;
}
// Prepare measure ****************************************************************
qDebug()<<"Debug: Prepare measure";
QStringList lines = conf->getConf_lines(); //read all rows of config files
record_time_100ms = lines.count()-9; // lines Audio config data + end lines
record_time_msec = record_time_100ms * 100; //msec conversion
for(i=0; i < (uint32_t)lines.length(); i++) //prepare single rows of config files
{
//uint32_t j = 0;
QString uart;
QString uart_hex;
if(i > 5 && i < lines.length())
{
QStringList speed_chunks = lines.at(i).split(","); //split rows by decimal point
m1 = speed_chunks.at(2).toInt();
m2 = speed_chunks.at(3).toInt();
m3 = speed_chunks.at(4).toInt();
m4 = speed_chunks.at(5).toInt();
hextest.resize(10);
hextest[0]=255;
hextest[1]=m1>>8;
hextest[2]=m1;
hextest[3]=m2>>8;
hextest[4]=m2;
hextest[5]=m3>>8;
hextest[6]=m3;
hextest[7]=m4>>8;
hextest[8]=m4;
hextest[9]=238;
qDebug()<< "Transfer data: " << i-8 << " from " << lines.count()-9 << " rows transmitted";
qDebug() << "Config file: " << filename << " is processed";
m_serial.write(hextest);
m_serial.waitForBytesWritten(1000);
QThread::usleep(50000);
}//if(lines.at(i).contains(",")) end }//for end
}//for end
//Beep
// Measurement ******************************************************************
qDebug()<<"Debug: Measurement in progress";
QEventLoop event_loop(this); //create method class QEventLoop
QTimer exit_timer(this); //create method class QTimer
exit_timer.setSingleShot(true); //set timer in mode singleShot
connect(&exit_timer, SIGNAL(timeout()), &event_loop, SLOT(quit())); //connect exit timer to event loop slot
QThread::msleep(1500);
QString path = SAVE_AUDIO_PATH+filename.left( filename.lastIndexOf( '.' ) )+"_"+QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");
//QThread::msleep(1500);
m_file.setFileName(path+".log");
//m_audio->StartRecording(path+".wav");
m_audio->StartRecording(path+".wav", record_time_msec);//+0.6
//exit_timer.start(15000);
exit_timer.start(record_time_msec);//event loop timer durring measure time
event_loop.exec();
qDebug()<<"Measurement takes " << record_time_msec << " seconds";
// Stop measure ************************************
QThread::msleep(2000);
stm=0;
record_time_msec = 0;
measure_cnt++;
// All configs files done *********************************
if(measure_cnt>=config_files_cnt)
{
qDebug()<<"All measure done";
qApp->quit();
}
}//foreach
}//processMeas()
// ************************************************************************************************
// Data from STM32 receive
void Measure::readRequest()
{
m_file.open(QIODevice::WriteOnly | QIODevice::Append);
m_file.write(m_serial.readAll());
m_file.close();
}
// ************************************************************************************************
// save received data to log File
void Measure::saveFile(QByteArray buffer)
{
m_file.write(buffer);
}
Recordings are always little bit longer, so its a not stochastic error :
On the picture are 4 same config-files, two time
EDIT:
I change a code to:
m_audio->StartRecording(path+".wav", record_time_msec+5000);
exit_timer.start(record_time_msec+5000);//event loop timer
event_loop.exec();
an get:
But how can I start my measure delayed? (I want to skip beginning Sound (Buzzer))?
Related
Using QAudioOut Im trying to play data that is stored in a QByteArray in a sequence... this works when there is little data being appended, however when the data gets too much, lets say a 2~3 hour RAW PCM appending from different combinations this data to a QByteArray all at once will result in a std::bad_alloc due to the heap that's not big enough to hold all the data at the same time.
I know where the problem occurs and I think I have a possible solution, its just I have no idea on how to go about implementing it.
Below is a converted function that takes the values in the list
first one 440Hz for 1800000 msec and created RAW PCM square wave. Which works then appends it to a QByteArray then plays it.
This will work if there isn't a lot of appended data form multiple added sequences.
Im looking for a way to do one at a time from the list then create the wave, play that one for x milliseconds then move on to the next entry in the MySeq list. The list can contain large sequences of 3 minute frequencies that runs for hours.
QStringList MySeq;
MySeq << "1:440:180000";
MySeq << "1:20:180000";
MySeq << "1:2120:180000";
MySeq << "1:240:180000";
MySeq << "1:570:180000";
foreach(QString seq, MySeq)
{
QStringList Assits = seq.split(":");
qDebug() << "Now At: " << seq;
QString A = Assits.at(0);
QString B = Assits.at(1);
QString C = Assits.at(2);
qreal amplitude = A.toInt();
float frequency = B.toFloat();
int msecs = C.toInt();
qreal singleWaveTime = amplitude / frequency;
qreal samplesPerWave = qCeil(format->sampleRate() * singleWaveTime);
quint32 waveCount = qCeil(msecs / (singleWaveTime * 1000.0));
quint32 sampleSize = static_cast<quint32>(format->sampleSize() / 8.0);
QByteArray data(waveCount * samplesPerWave * sampleSize * format->channelCount(), '\0');
unsigned char* dataPointer = reinterpret_cast<unsigned char*>(data.data());
for (quint32 currentWave = 0; currentWave < waveCount; currentWave++)
{
for (int currentSample = 0; currentSample < samplesPerWave; currentSample++)
{
double nextRadStep = (currentSample / static_cast<double>(samplesPerWave)) * (2 * M_PI);
quint16 sampleValue = static_cast<quint16>((qSin(nextRadStep) > 0 ? 1 : -1) * 32767);
for (int channel = 0; channel < format->channelCount(); channel++)
{
qToLittleEndian(sampleValue, dataPointer);
dataPointer += sampleSize;
}
}
}
soundBuffer->append(data); // HERE IS THE Std::Bad_Alloc
output->start(outputBuffer);
qDebug() << data.size()
}
I wish to fill the QByteArray with only one sequence at a time then Play it with QAudioOutput then clear the ByteArray then load the next sequence repeat until all sequences are done in the QStringList.
The problem with this approach now is that QAudioOutput is asynchronous and doesn't wait for the first sequence to finish
If I loop over the list as demonstrated above they load one after the other with only the last frequency actually playing. its like the loop keep overwriting the previous sequence.
Im not sure if QEventLoop (Something I haven't used yet) is needed here or Threading. I have tried a couple of different approaches with no success. Any advice would be greatly appreciated. This is a continuation of the following question I had about wave files and data and frequency generations located here
Qt C++ Creating a square audio tone wave. Play and saving it
mainWindows.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtCore>
#include <QtMultimedia/QAudioOutput>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void playbackFinished();
private slots:
void appendSound();
void on_pushButton_Run_clicked();
void on_pushButton_Stop_clicked();
private:
Ui::MainWindow *ui;
QByteArray *soundBuffer;
QBuffer *outputBuffer;
QAudioFormat *format;
QAudioOutput *output;
};
#endif // MAINWINDOW_H
mainWindows.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
int sampleRate = 44100;
int channelCount = 2;
int sampleSize = 16;
const QString codec = "audio/pcm";
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
soundBuffer = new QByteArray();
format = new QAudioFormat();
format->setSampleRate(sampleRate);
format->setChannelCount(channelCount);
format->setSampleSize(sampleSize);
format->setCodec(codec);
format->setByteOrder(QAudioFormat::LittleEndian);
format->setSampleType(QAudioFormat::UnSignedInt);
output = new QAudioOutput(*format, this);
connect(output, SIGNAL(stateChanged(QAudio::State)), this, SLOT(playbackFinished()));
outputBuffer = new QBuffer(soundBuffer);
if (outputBuffer->open(QIODevice::ReadOnly) == false) {
qCritical() << "Invalid operation while opening QBuffer. audio/pcm";
return;
}
}
MainWindow::~MainWindow()
{
delete ui;
delete soundBuffer;
delete format;
delete output;
delete outputBuffer;
}
void MainWindow::playbackFinished()
{
if (output->state() == QAudio::IdleState)
{
qDebug() << "Playback finished";
}
}
void MainWindow::appendSound()
{
QStringList MySq;
MySq << "1:440:180000";
MySq << "1:20:180000";
MySq << "1:2120:180000";
MySq << "1:240:180000";
MySq << "1:570:180000";
MySq << "1:570:180000";
MySq << "1:570:180000";
MySq << "1:850:180000";
MySq << "1:1570:180000";
MySq << "1:200:180000";
MySq << "1:50:180000";
MySq << "1:85:180000";
MySq << "1:59:180000";
MySq << "1:20:180000";
foreach(QString seq, MySq)
{
QStringList Assits = seq.split(":");
qDebug() << "Now At: " << seq;
QString A = Assits.at(0);
QString B = Assits.at(1);
QString C = Assits.at(2);
qreal amplitude = A.toInt();
float frequency = B.toFloat();
int msecs = C.toInt();
msecs = (msecs < 50) ? 50 : msecs;
qreal singleWaveTime = amplitude / frequency;
qreal samplesPerWave = qCeil(format->sampleRate() * singleWaveTime);
quint32 waveCount = qCeil(msecs / (singleWaveTime * 1000.0));
quint32 sampleSize = static_cast<quint32>(format->sampleSize() / 8.0);
QByteArray data(waveCount * samplesPerWave * sampleSize * format->channelCount(), '\0');
unsigned char* dataPointer = reinterpret_cast<unsigned char*>(data.data());
for (quint32 currentWave = 0; currentWave < waveCount; currentWave++)
{
for (int currentSample = 0; currentSample < samplesPerWave; currentSample++)
{
double nextRadStep = (currentSample / static_cast<double>(samplesPerWave)) * (2 * M_PI);
quint16 sampleValue = static_cast<quint16>((qSin(nextRadStep) > 0 ? 1 : -1) * 32767);
for (int channel = 0; channel < format->channelCount(); channel++)
{
qToLittleEndian(sampleValue, dataPointer);
dataPointer += sampleSize;
}
}
}
soundBuffer->append(data); // <-- STD::Bad_alloc Not enough memory on heap for appending all the frequencies at once in buffer
output->start(outputBuffer);
qDebug() << data.size();
}
}
void MainWindow::on_pushButton_Run_clicked()
{
appendSound();
}
void MainWindow::on_pushButton_Stop_clicked()
{
output->stop();
soundBuffer->clear();
output->reset();
qDebug() << "Playback Stopped";
}
I came up with a solution using QThread and a Interpreter for that thread to wait for more events before continuing the next sequence in the series.
By doing this I don't need to load the full 3~4 hour PCM data into a QBufferArray all at the same time but rather break it up. Run a smaller sequence then wait on the thread to finish then load the next sequence in line and so on until all of them are done playing.
No more std::bad_alloc since the thread only uses around 80mb on the heap at any given time.
all
I want to use QUdpSocket to send udp packet to get config parameter from specific server,but It failed and I can not capture the sending packet using wireshark.here is my code:
CGetConfig.cpp:
CGetConfig::CGetConfig(const QString &conf_server,const uint16_t port)
:m_conf_server(conf_server)
,m_port(port)
{
m_socket = NULL;
}
CGetConfig::~CGetConfig()
{}
void CGetConfig::init()
{
// create a QUDP socket
m_socket = new QUdpSocket(this);
m_socket->bind(QHostAddress::LocalHost, 12345);
connect(m_socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
m_ip_addr = get_ip_address(m_conf_server);
}
bool CGetConfig::get_reflector(const QString &mac)
{
qDebug() << "CGetConfig::get_reflector():Entry\n";
if(m_ip_addr.isEmpty())
{
qDebug() << "CGetConfig::get_reflector():ip address of cofnig server could not be resolved\n";
return 0;
}
QString msg("id=1&mac=");
msg+= mac;
msg+= "&get_config=fw_type=v.1,cfg_ver=4,set_ver=0,ip=192.168.1.101";
qDebug() << m_ip_addr;
qDebug() << m_port;
qDebug() << msg.toLatin1();
int count = 0;
while(count < 3)
{
int t = m_socket->writeDatagram(msg.toLatin1(), QHostAddress(m_ip_addr), m_port);
count++;
}
}
Main.cpp
CGetConfig cfg(cfg_server,cfg_port);
cfg.init();
local_mac = "00d033120001";
cfg.get_reflector(local_mac);
Can anyone help me figure out the problem?
I would like to use ZeroMQ(4.1.2) with Qt (5.2.1).
Idea is to have zmq pub/sub (where server is outside) and sub is qt app.
Currently receive in Qt app runs once, could someone drop hint?
Should ZeroMQ receiver be implemented in some other way?
Currently my code looks like:
mainwindow.h
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
void readZMQData();
private:
Ui::MainWindow *ui;
QSocketNotifier *qsn;
void *context;
void *subscriber;
};
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
/***** ZMQ *****/
context = zmq_ctx_new ();
subscriber = zmq_socket (context, ZMQ_SUB);
int rc = zmq_connect (subscriber, "tcp://localhost:5556");
char *filter = "";
rc = zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE,filter, strlen (filter));
unsigned int fd=0;
size_t fd_size = sizeof(fd);
rc = zmq_getsockopt(subscriber,ZMQ_FD,&fd,&fd_size);
qsn = new QSocketNotifier(fd, QSocketNotifier::Read, this);
connect(qsn, SIGNAL(activated(int)), this, SLOT(readZMQData()), Qt::DirectConnection);
}
MainWindow::~MainWindow()
{
zmq_close (this->subscriber);
zmq_ctx_destroy (this->context);
delete ui;
}
void MainWindow::readZMQData()
{
qsn->setEnabled(false);
qDebug() << "Got data!";
int events = 0;
std::size_t eventsSize = sizeof(events);
zmq_getsockopt(subscriber,ZMQ_EVENTS, &events, &eventsSize);
if(events & ZMQ_POLLIN){
qDebug() << " ====== Data to read ======";
char *string = s_recv(subscriber);
qDebug() << "DATA: " << string;
free(string);
}
qsn->setEnabled(true);
}
And server app is (from ZeroMQ examples):
#include "zhelpers.h"
int main (void)
{
// Prepare our context and publisher
void *context = zmq_ctx_new ();
void *publisher = zmq_socket (context, ZMQ_PUB);
int rc = zmq_bind (publisher, "tcp://*:5556");
assert (rc == 0);
// Initialize random number generator
srandom ((unsigned) time (NULL));
while (1) {
// Get values that will fool the boss
int zipcode, temperature, relhumidity;
zipcode = randof (100000);
temperature = randof (215) - 80;
relhumidity = randof (50) + 10;
// Send message to all subscribers
char update [20];
sprintf (update, "%05d %d %d", zipcode, temperature, relhumidity);
s_send (publisher, update);
}
zmq_close (publisher);
zmq_ctx_destroy (context);
return 0;
}
First tnx for helping out,
I've found the issue, when ZeroMQ notifies that there is message to read you need to read them all, not just first one.
void MainWindow::readZMQData(int fd)
{
qsn->setEnabled(false);
int events = 0;
std::size_t eventsSize = sizeof(events);
zmq_getsockopt(subscriber,ZMQ_EVENTS, &events, &eventsSize);
if(events & ZMQ_POLLIN){
qDebug() << " ====== Data to read ======";
char *string;
// THIS IS THE TRICK! READ UNTIL THERE IS MSG
while((string = s_recv_nb(subscriber)) != NULL){
qDebug() << "DATA: " << string;
free(string);
}
}
qsn->setEnabled(true);
}
The socket notifier looks like it should work. Have you read the docs on handling it properly? Especially if you are on Windows, it looks like there are special ways to handle it when doing the read... disabling, reading, etc.
http://doc.qt.io/qt-5/qsocketnotifier.html#details
Hope that helps.
As it is not clear what s_recv_nb(zmq::socket_t & socket) is, I'll provide my - slightly more detailed - implemetation of:
void MainWindow::readZMQData()
{
qsn->setEnabled(false);
int events = 0;
std::size_t eventsSize = sizeof(events);
zmq_getsockopt(subscriber,ZMQ_EVENTS, &events, &eventsSize);
if(events & ZMQ_POLLIN){
qDebug() << " ====== Data to read ======";
char *string;
int64_t more;
size_t more_size = sizeof (more);
do {
/* Create an empty ØMQ message to hold the message part */
zmq_msg_t part;
int rc = zmq_msg_init (&part);
assert (rc == 0);
rc = zmq_msg_recv (&part, subscriber, 0);
assert (rc != -1);
/* Determine if more message parts are to follow */
rc = zmq_getsockopt (subscriber, ZMQ_RCVMORE, &more, &more_size);
assert (rc == 0);
string = (char*) zmq_msg_data(&part);
qDebug() << QString(string) ; // << "more" << more;
zmq_msg_close (&part);
} while (more);
}
qsn->setEnabled(true);
}
And one more remark: in case of Windows 64 the filedescriptor fdshould be uint64_t as in zmq_getsockopt returns EINVAL on windows x64 when local address of ZMQ_FD option_val passed
I am trying to record audio from the default microphone present in my desktop and store it in QFile.
Finally I want to play the recorded file using windows media player. The issue is that QAudioInput has a method bytesReady() which always returns 0 in my case. Even if the audio state is QAudio::ActiveState the bytesReady() shows 0 bytes implying that there are no audio bytes to read from the microphone. The system microphone works just fine. My code gets perfectly compiled, I also get a file in the specifed location with 80KB size, but the file doesn't play with windows media player even if saved as a .wav, it returns an error.
The output window shows bytesReady as 0 in my case everytime. I suspect the QAudioInput is not able to read audio data from microphone.
Could you please help me find mistakes in my code?
`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;
};
// cpp file starts here
#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 (*.raw)"));
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();
if(!default_deviceName.isEmpty())
{
preferred_format = info.preferredFormat();
QString codec = preferred_format.codec();
int sampleRate = preferred_format.sampleRate();
int sampleSize = preferred_format.sampleSize();
int channelCount = preferred_format.channelCount();
int sampleType = preferred_format.sampleType();
int byteOrder = preferred_format.byteOrder();
qDebug() << "codec:" << codec.toLatin1() << "sampleRate :" << sampleRate << "sampleSize:" << sampleSize << "channel Count:" << channelCount << "sample type:" <<sampleType
<< "byteOrder:" << byteOrder;
}
}
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);
connect(audioInput, SIGNAL(notify()), this, SLOT(notified()));
connect(audioInput,SIGNAL(stateChanged(QAudio::State)),this, SLOT(handleAudioInputState(QAudio::State)));
QTimer::singleShot(10000, this, SLOT(stopRecording()));
//audioInput->setBufferSize(4096);
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 calling QAudioInput start():" << audioInput->bufferSize();
qDebug() << "bytesReady = " << audioInput->bytesReady()
<< ", " << "elapsedUSecs = " <<audioInput->elapsedUSecs()
<< ", " << "processedUSecs = "<<audioInput->processedUSecs();
}
}`
The output displays as follows:
device_name: "Microphone (High Definition Aud"
device_name: "default"
codec: "audio/pcm" sampleRate : 11025 sampleSize: 8 channel Count: 1 sample type: 1 byteOrder: 1
Default format not supported, try to use nearest format
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 = 1998000 , processedUSecs = 2000000
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 3003000 , processedUSecs = 3000000
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 4000000 , processedUSecs = 4000000
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 5006000 , processedUSecs = 5000000
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 6001000 , processedUSecs = 6000000
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 7005000 , processedUSecs = 7000000
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 8002000 , processedUSecs = 8000000
Error State: 0
platform buffer size after called QAudioInput start(): 1600
bytesReady = 0 , elapsedUSecs = 8997000 , processedUSecs = 9000000
Audio State: 2
Error State: 0
Having compared your code to the example in the Qt documentation, you're using the notified signal to handle the QAudio::ActiveState, whereas the example code connects a slot to the stateChanged signal: -
void AudioInputExample::handleStateChanged(QAudio::State newState)
{
switch (newState) {
case QAudio::StoppedState:
if (audio->error() != QAudio::NoError) {
// Error handling
} else {
// Finished recording
}
break;
case QAudio::ActiveState:
// Started recording - read from IO device
break;
default:
// ... other cases as appropriate
break;
}
}
As notify() states: -
This signal is emitted when x ms of audio data has been processed the interval set by setNotifyInterval
Could the interval be zero?
However, I recommend following the example code as shown in the documentation and use the stateChanged signal, rather than notify.
Consider PHDEBUG or PHDBG as qDebug() and see the following (I think your missing point is the QIODevice which stand as a buffer.):
Reader.cpp :
#include "PhLtcReader.h"
PhLtcReader::PhLtcReader(QObject *parent) :
QObject(parent),
_input(NULL),
_position(0),
_buffer(NULL)
{
_decoder = ltc_decoder_create(1920, 3840);
PHDEBUG << "LTC Reader created";
}
bool PhLtcReader::init(QString input)
{
QList<QAudioDeviceInfo> list = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
if(list.isEmpty())
{
PHDEBUG << "No audio input device";
return false;
}
QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
foreach(QAudioDeviceInfo device, list)
{
if(device.deviceName() == input)
info = device;
}
PHDEBUG << "LTC input device :" << info.deviceName();
QAudioFormat format;
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleRate(48000);
format.setChannelCount(1);
format.setSampleSize(8);
format.setSampleType(QAudioFormat::SignedInt);
if(!info.isFormatSupported(format))
{
PHDEBUG << "Unsupported audio format";
return false;
}
_position = 0;
_input = new QAudioInput(info, format);
connect(_input, SIGNAL(notify()), this, SLOT(onNotify()));
_buffer = _input->start();
_input->setNotifyInterval(10);
_pauseDetector.start();
return true;
}
void PhLtcReader::close()
{
if(_input)
{
_input->stop();
delete _buffer;
_buffer = NULL;
delete _input;
_input = NULL;
}
}
QList<QString> PhLtcReader::inputList()
{
QList<QString> names;
QList<QAudioDeviceInfo> list = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
foreach(QAudioDeviceInfo device, list)
names.append(device.deviceName());
return names;
}
void PhLtcReader::onNotify()
{
QByteArray array = _buffer->readAll();
char max = 0;
for(int i = 0; i < array.count(); i++)
{
if(array.at(i) > max)
max = array.at(i);
}
ltc_decoder_write(_decoder, (ltcsnd_sample_t*)array.data(), array.count(), _position);
LTCFrameExt frame;
unsigned int *hhmmssff = new unsigned int[4];
while(ltc_decoder_read(_decoder, &frame))
{
PhFrame oldFrame = _clock.frame();
hhmmssff[0] = frame.ltc.hours_tens * 10 + frame.ltc.hours_units;
hhmmssff[1] = frame.ltc.mins_tens * 10 + frame.ltc.mins_units;
hhmmssff[2] = frame.ltc.secs_tens * 10 + frame.ltc.secs_units;
hhmmssff[3] = frame.ltc.frame_tens * 10 + frame.ltc.frame_units;
}
delete hhmmssff;
_position += array.count();
}
Reader.h
class PhLtcReader : public QObject
{
Q_OBJECT
public:
explicit PhLtcReader(QObject *parent = 0);
bool init(QString _input="");
void close();
static QList<QString> inputList();
private slots:
void onNotify();
private:
QAudioInput *_input;
qint64 _position;
QIODevice * _buffer;
};
#endif // PHLTCREADER_H
The answer to your question can be found in the output.
There is a line that says
Default format not supported, try to use nearest format
Which is the problem. The format you're using isn't supported by your platform. Try a different one or install the codecs/drivers to support that format.
I am working on USB WebCamera using OpenCv in Qt.The code works fine for taking images, saving images etc. But randomly it generates error "VIDIOC_QUERYCTRL: Input/output error" causing my whole qt application to shutdown.
Actually The Scenario of my application is as follow:
In MainWindow.c, I have a pushbutton, which is when pressed starts the camera:
void MainWindow::on_pushButton_continue_pressed()
{
camcapture = new CamCapture( imgResolution, defaultPath, this);
connect(camcapture, SIGNAL(imgChange(QString)), this, SLOT(changeImg(QString)));
camcapture->show();
}
and Here is piece of my CamCapture Class:
CamCapture::CamCapture( int Resolution, QString path, QWidget *parent) :
QFrame(parent),
ui(new Ui::CamCapture), timer_(this), counter_(0)
{
ui->setupUi(this);
/*----some variable initialization---*/
camInit();
timer_.start(100);
connect(&timer_,SIGNAL(timeout()), this,SLOT(captureLoop()));
}
void CamCapture::camInit()
{
capture_ = cvCaptureFromCAM(0);
if (!capture_)
{
qDebug()<<"cannot get webcam...";
ui->label_image->setText("No webcam!");
ui->label_image->setAlignment(Qt::AlignCenter);
buttonActiveStatus( false, false, false );
return;
}
cvGrabFrame(capture_); // Grabs frame from camera or file
image_ = cvRetrieveFrame(capture_); // Gets the image grabbed with cvGrabFrame
qDebug() << "image size : " << image_->width << "x" << image_->height;
qDebug() << "\n" << ui->label_image->x();
qDebug() << "\n" << ui->label_image->y();
}
QImage CamCapture::Ipl2QImage(const IplImage *newImage)
{
QImage qtemp;
if (newImage && cvGetSize(newImage).width > 0)
{
int x;
int y;
char* data = newImage->imageData;
qtemp= QImage(newImage->width, newImage->height,QImage::Format_RGB32 );
for( y = 0; y < newImage->height; y++, data +=newImage->widthStep )
for( x = 0; x < newImage->width; x++)
{
uint *p = (uint*)qtemp.scanLine (y) + x;
*p = qRgb(data[x * newImage->nChannels+2],
data[x * newImage->nChannels+1],data[x * newImage- >nChannels]);
}
}
return qtemp;
}
void CamCapture::captureLoop()
{
if ( !capture_ )
{
return;
}
cvGrabFrame(capture_);
image_ = cvRetrieveFrame(capture_);
if (image_)
{
counter_ ++;
qImage_ = Ipl2QImage(image_);
ui->label_image- >setPixmap(QPixmap::fromImage(qImage_.scaled(width(),height()),Qt::AutoColor));
}
}
void CamCapture::on_pushButton_cancel_pressed()
{
cvReleaseCapture( &capture_ );
cvDestroyAllWindows();
delay(100);
qDebug() << "nb frames :" << counter_;
CamCapture::close();
}
void CamCapture::on_pushButton_capture_pressed()
{
savePath = _imgPath;
timer_.stop();
frame = cvQueryFrame(capture_); // Gets the image grabbed with cvGrabFrame
}
void CamCapture::on_pushButton_retake_pressed()
{
timer_.start(100);
captureLoop();
}
void CamCapture::on_pushButton_save_pressed()
{
int iwidth = _imgWidth * _imgResolution * scaledFactor;
int iheight = _imgHeight * _imgResolution * scaledFactor;
QString str = savePath;
IplImage *small;
small = cvCreateImage(cvSize(iwidth,iheight), 8, 3);
cvResize(frame, small);
cvSaveImage(savePath.toUtf8().constData(),small);
delay(100);
_imgNum++;
emit imgChange(savePath);
on_pushButton_cancel_pressed();
}
The above code randomly generates error ( causing my application shutdowm ) as follow:
Debugging starts
&"warning: GDB: Failed to set controlling terminal: Invalid argument\n"
Corrupt JPEG data: bad Huffman code
image size : 640 x 480
5
10
nb frames : 11
VIDIOC_QUERYCTRL: Input/output error
Debugging has finished
Commonly, the Error is generated Either while pressing pushButton_continue from MainWindow.c or While pressing pushButton_Save from CamCapture.c
Unable to find any solution on google.
Need some suggestions/help/link to solve this issue.
Thanks in advance.