Need some help with QIODevice based buffer class
-
I wrote QIODevice based class, which I use as my audio buffer. It consist from two arrays. When I write data, I write it till buffer reach end then switch to second buffer and continue writing, and so on. When I read data a do the same thing.
@#ifndef AUDIOBUFFER_H
#define AUDIOBUFFER_H#include <QAudioFormat>
#include <QIODevice>
#include <QMutex>
#include <QDebug>
#include <QtEndian>class AudioBuffer : public QIODevice
{
Q_OBJECTpublic:
//----------------------------------------------------------------------------------------------------------------------------------
AudioBuffer(QObject parent = NULL, int bufSize = 1411) : QIODevice(parent)
{
m_bufSize = bufSize10/10000/;m_buffer1 = new const char[m_bufSize];
m_buffer2 = new const char[m_bufSize];m_readCursor = 0;
m_writeCursor = 0;qMemSet((void *)m_buffer1,0,m_bufSize);
qMemSet((void *)m_buffer2,0,m_bufSize);m_readBuffer = m_buffer1;
m_writeBuffer = m_buffer1;m_bytesReady = 0;
/* m_flag = false;*/
}
//----------------------------------------------------------------------------------------------------------------------------------
~AudioBuffer()
{
delete m_buffer1;
delete m_buffer2;
}
//----------------------------------------------------------------------------------------------------------------------------------
void start()
{
if(!isOpen())
open(QIODevice::ReadWrite);
}
//----------------------------------------------------------------------------------------------------------------------------------
void stop()
{
delete m_buffer1;
delete m_buffer2;close();
}
//----------------------------------------------------------------------------------------------------------------------------------
qint64 readData(char * data, qint64 len)
{
// if (m_flag == false){
// if (bytesAvailable()>1000)
// {
// m_flag = true;
// }
// else
// return 0;
// }if(len > m_bytesReady) len = m_bytesReady;
int freeBytes = (m_bufSize - m_readCursor);
if(len <= freeBytes)
{
qMemCopy(data,(void *)m_readBuffer,len);
m_readCursor += len;m_bytesReady -= len;
return len;
}qMemCopy(data,(void *)m_readBuffer,freeBytes);
switchBuffer(m_readBuffer);
int leftBytes = len-freeBytes;
qMemCopy(data,(void *)m_readBuffer,leftBytes);
m_readCursor = leftBytes;
m_bytesReady -= len;
return len;
}
//----------------------------------------------------------------------------------------------------------------------------------
qint64 read(char * data, qint64 len)
{
return readData(data,len);
}
//----------------------------------------------------------------------------------------------------------------------------------
qint64 readBlock ( char * data, quint64 size )
{
return readData(data,size);
}
//----------------------------------------------------------------------------------------------------------------------------------
qint64 writeData(const char *data, qint64 len){int freeBytes = (m_bufSize - m_writeCursor);
if(len <= freeBytes){
qMemCopy((void *)m_writeBuffer,data,len);
m_writeCursor += len;
m_bytesReady += len;
return len;
}qMemCopy((void *)m_writeBuffer,data,freeBytes);
switchBuffer(m_writeBuffer);
int leftBytes = len-freeBytes;
if(leftBytes > m_bufSize) { leftBytes = m_bufSize; m_bytesReady += freeBytes + m_bufSize; } else m_bytesReady += len;
qMemCopy((void *)m_writeBuffer,data,leftBytes);
m_writeCursor = leftBytes;
return len;
}
//----------------------------------------------------------------------------------------------------------------------------------
qint64 write(const char *data, qint64 len){return writeData(data,len);
}
//----------------------------------------------------------------------------------------------------------------------------------
void switchBuffer(const char * buffer)
{
if(buffer == m_buffer1)
buffer = m_buffer2;
else
buffer = m_buffer1;
}
//----------------------------------------------------------------------------------------------------------------------------------
qint64 bytesAvailable() const
{
return m_bytesReady;
}
//----------------------------------------------------------------------------------------------------------------------------------
private:
const char * m_buffer1;
const char * m_buffer2;
const char * m_readBuffer;
const char * m_writeBuffer;
qint64 m_readCursor;
qint64 m_writeCursor;
qint64 m_bufSize;
qint64 m_bytesReady;
/bool m_flag;/};
#endif//AUDIOBUFFER_H@
I use m_readCursor and m_writeCursor to continue reading and writing, m_bytesReady to know How much bytes I can read. But when my m_bufSize is to small, like in this code:
@m_bufSize = bufSize*10;@
I've got a crash in read data right here:
@qMemCopy(data,(void *)m_readBuffer,freeBytes);@
because my freeByetes value is < 0 after one iteration. Waiting for your comments and modifications, optimizations. -
Though I don't know well about QIODevice class, but generally handling audio buffer requires us to use thread lock mechanism(like QMutex ..). Did you consider this?
BTW, what kind of application you are building? I love DAW things. :-)
-
This is just buffer class, and as you said the threads is needed, and I use it in other place in thread. So all with threads is OK :) This will be something like net player which uses RTSP session and receives data thou RTP and play it on a speakers.
-
I solve it by modifying readData like this:
@qint64 readData(char * data, qint64 len)
{
// if (m_flag == false){
// if (bytesAvailable()>1000)
// {
// m_flag = true;
// }
// else
// return 0;
// }if(len > m_bytesReady) len = m_bytesReady;
int freeBytes = (m_bufSize - m_readCursor);
if(len <= freeBytes)
{
qMemCopy(data,(void *)m_readBuffer,len);
m_readCursor += len;m_bytesReady -= len;
return len;
}qMemCopy(data,(void *)m_readBuffer,freeBytes);
switchBuffer(m_readBuffer);
int leftBytes = len-freeBytes; if(leftBytes > m_bufSize) { m_bytesReady -= freeBytes + m_bufSize; qMemCopy(data,(void *)m_readBuffer,m_bufSize); m_readCursor = m_bufSize; return freeBytes + m_bufSize; } qMemCopy(data,(void *)m_readBuffer,leftBytes); m_readCursor = leftBytes; m_bytesReady -= len; return len;
}@
and writeData like this:
@qint64 writeData(const char *data, qint64 len){int freeBytes = (m_bufSize - m_writeCursor);
if(len <= freeBytes){
qMemCopy((void *)m_writeBuffer,data,len);
m_writeCursor += len;
m_bytesReady += len;
return len;
}qMemCopy((void *)m_writeBuffer,data,freeBytes);
switchBuffer(m_writeBuffer);
int leftBytes = len-freeBytes;
if(leftBytes > m_bufSize) { m_bytesReady += freeBytes + m_bufSize; qMemCopy((void *)m_writeBuffer,data,m_bufSize); m_writeCursor = m_bufSize; return freeBytes + m_bufSize; } qMemCopy((void *)m_writeBuffer,data,leftBytes); m_writeCursor = leftBytes; m_bytesReady += len; return len;
}@
But now I hear clicks which depend on my buffer size if it equal to this:
@ m_bufSize = bufSize*5;@
It's a lot of clicks, if I change 5 to 10 it less clicks so i put there 1000. :) -
I found the place when it clicks. It clicks when I reach the end of buffer and make switchBuffer, so thats why when I make my buffer bigger it clicks rare, but why and how to solve it ?