PDA

View Full Version : combining external lib callbacks with QT signals



plori
26th January 2012, 17:11
Hello,

I'm trying to set up a GUI with QT using PortAudio to capture sound. For contious recording i use two buffer which I switch, when one is filled with Data. Now I want to use a new thread to process the full Buffer (save data). That's where the Problem lies... I have created that thread and tryed to interface it via a signal. But the signal is emitted from within the callback thread and not the main thread. For some reason this is not working.

My savethread class:


class SaveBuffer : public QThread
{
Q_OBJECT

public:
SaveBuffer(QObject *parent = 0);
~SaveBuffer();

void process();

protected:
void run();

protected:
bool finish;

private:

QMutex mutex;
QWaitCondition condition;
SDataStruct sData;
};




#include "SaveBuffer.h"

SaveBuffer::SaveBuffer(QObject *parent)
: QThread(parent)
{
sData.file.setFileName("recorded.raw");
sData.file.open(QIODevice::Append);
}

SaveBuffer::~SaveBuffer()
{
//mutex.lock();
condition.wakeOne();
//mutex.unlock();

sData.file.close();
wait();
}

void SaveBuffer::run()
{
forever
{
QMutexLocker locker(&mutex);

QFile *file = &sData.file;
int frameIndex = *sData.FrameIndex;
SAMPLE *buffer = sData.buffer;

QDataStream out(file);
out.setByteOrder(QDataStream::LittleEndian);
for(int k=0;k<frameIndex;k++)
{
out << (qreal)buffer[k];
}
condition.wait(&mutex);//put thread to sleep
}
};

void SaveBuffer::process(DataStruct* incData)
{
QMutexLocker locker(&mutex);

if (!isRunning()) {
start(LowPriority);
} else {
condition.wakeOne();
}
}


My window class:


class EEGacquisition : public QMainWindow
{
Q_OBJECT

public:
EEGacquisition(QWidget *parent = 0, Qt::WFlags flags = 0);
~EEGacquisition();
void processDataEmitter(void*);

private:
Ui::EEGacquisitionClass ui;
SaveBuffer sthread;


signals:
void processData();

};




int recordCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData,
void *ui);

EEGacquisition::EEGacquisition(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);

//connects
connect(ui.pushButton_measure,SIGNAL(clicked()),th is,SLOT(pushButton_measure_clicked()),Qt::DirectCo nnection);

/*---portaudio setup---*/
[...]
}
}


void EEGacquisition::processDataEmitter(void *user_int)
{
// problem here if i emit a signal I am still in record callback
// I cannot connet this signal
}

/////
//callback for recording audio data
/////
static int recordCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData,
void *user_int)
{
[...]

//at some point emit save signal!!!
ui->processDataEmitter();

[...]

return paContinue;//0
}


I also tried directly calling the process() function in sthread, but doing so led to an exeption, because the call wasnt from the main window thread.

Can someone please explain some way to start the save thread?

Thanks

wysota
30th January 2012, 02:07
Don't subclass QThread. Instead create an instance of QThread and encapsulate whole functionality of your worker thread in a QObject subclass. Then use QObject::moveToThread() to move that object to the newly created thread. Alternatively don't use signals and slots. Instead of that it should be possible to use a wait condition to trigger the waiting thread (if I understood correctly what you wanted).