Send raw data to QAudioOutput.
-
I've got QAudioOutput which initialized by next format:
@QAudioFormat format;
// Set up the format, eg.
format.setFrequency(44100);
format.setChannels(2);
format.setSampleSize(16);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::UnSignedInt);QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); if (!info.isFormatSupported(format)) { qWarning()<<"raw audio format not supported by backend, cannot play audio."; return; }@
I've got a class subclassed from QIODevice to store incoming data which uses like a buffer:
@#ifndef AUDIOBUFFER_H
#define AUDIOBUFFER_H#include <QAudioFormat>
#include <QIODevice>
#include <QMutex>class AudioBuffer : public QIODevice
{
Q_OBJECT
public:
struct block
{
char * ptr;
qint64 len;
int index;
};
//----------------------------------------------------------------------------------------------------------------------------------
AudioBuffer(/const QAudioFormat &format,/ QObject *parent = NULL) : QIODevice(parent)
{
// const char * someData = "12MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWQuhaSSSSSSSSSSSSSSSSSSSSSSSSSSss";
// writeData(someData,sizeof(someData));
}
//----------------------------------------------------------------------------------------------------------------------------------
~AudioBuffer()
{
clear();
}
//----------------------------------------------------------------------------------------------------------------------------------
void start()
{
if(!isOpen())
open(QIODevice::ReadWrite);
}
//----------------------------------------------------------------------------------------------------------------------------------
void stop()
{
close();
}
//----------------------------------------------------------------------------------------------------------------------------------
qint64 readData(char * data, qint64 maxlen)
{
QMutexLocker mutexLocker(&m_mutex);start(); if(m_buffer.isEmpty()) return 0; int length = maxlen; int size = 0; while (m_buffer.isEmpty() == false) { block bl = m_buffer.at(0); if (bl.len <= length) { memcpy(data+size, bl.ptr, bl.len); m_buffer.removeAt(0); delete [] bl.ptr; length -= bl.len; size += bl.len; continue; } memcpy(data+size, bl.ptr, length); bl.len -= length; m_buffer[0] = bl; memcpy(bl.ptr, bl.ptr+length, bl.len); size += length; length = 0; break; } if (length > 0) memset(data + (maxlen - length), 0xCC, length); return maxlen; }
//----------------------------------------------------------------------------------------------------------------------------------
qint64 writeData(const char *data, qint64 len)
{QMutexLocker mutexLocker(&m_mutex); start(); char * ptr = new char[len]; memcpy(ptr,data,len); block bl; bl.ptr = ptr; bl.len = len; m_buffer.append(bl); return len; }
//----------------------------------------------------------------------------------------------------------------------------------
void clear(){
QMutexLocker mutexLocker(&m_mutex);for(int i = 0; i<m_buffer.count(); i++) { block bl = m_buffer.at(i); delete [] bl.ptr; } m_buffer.clear(); }
//----------------------------------------------------------------------------------------------------------------------------------
private:
QList<block> m_buffer;
QMutex m_mutex;
};#endif//AUDIOBUFFER_H@
Then I do the following thing:
@
AudioBuffer * m_buf;
QAudioOutput * m_output;m_buf = new AudioBuffer();
m_buf->start();m_output = new QAudioOutput(format);
m_output->start(m_buf);
@
And later add data in another place:
@m_buf->writeData((const char *)data,dataSize);@But after all this manipulations I hear no sound at output.
-
I replace AudioBuffer By new variable <code>QIODevice * m_dev;</code> And do the following declarations
@
m_dev = m_output->start();
@
and replace
@m_buf->writeData((const char *)data,dataSize);@
by
@m_dev->write((const char *)data,dataSize);@
And now I get a beautiful noise in output but not that music which I put there. An this noise is interrupt periodically. But it finishes when data transmit finishes. Maybe something wrong with format?As a source I am using wav file 44100 Hz 16 bit stereo, which i transmit over network an receive data by portions and write it actually here:
@m_buf->writeData((const char *)data,dataSize);@
So if I use a file to receive this data, and after receiving I open it, it's contains the music that I transmitt.Edit: fixed code formatting and merged two posts; Andre
-
Now I'm using my buffer such as QIODevice @m_buf = (AudioBuffer *)m_output->start();@ and get the same. I change the file that I transmit to another one, and notice that I can hear music, but it's very distorted, and interrupts as I wrote previously. But one more notice that the high freq sounds with low volume hears better than others.
-
RTP defines all values to be transmitted in big-endian, so no surprise there;-)
http://developer.qt.nokia.com/doc/qt-4.8/qtendian.html to the rescue.
-
-
I write function:
@bool SpeakerSink::toLittleEndian( const char * src, int size, int nBits)
{
if(src == NULL)
return false;for (int i = 0; i < size; i+=nBits) { qint16 val = qFromBigEndian<qint16>((const uchar*)(src+i)); qMemCopy((void*)(src+i),&val,nBits); } return true;
}@
It solve task of converting from big-endian to little-endian and in headphones I get the same result(I mean sound is recognizable but bad quality) as if my server will transmit data without conversation to big-endian. But sound still distorted and interrupts. -
-
Sorry, no idea what kind of data you send around your network;-)
Why do you have nBits in the toLittleEndian method shown above? Anything but nBits == 2 breaks the method, doesn't it? The name is rather confusing, too... shouldn't it at least be nBytes?
-
I rewrite my audio buffer class. Now it looks like this:
@#ifndef AUDIOBUFFER_H
#define AUDIOBUFFER_H#include <QAudioFormat>
#include <QIODevice>
#include <QMutex>
#include <QDebug>class AudioBuffer : public QIODevice
{
Q_OBJECTpublic:
//----------------------------------------------------------------------------------------------------------------------------------
AudioBuffer(/const QAudioFormat &format,/ QObject parent = NULL, int bufSize = 1400) : QIODevice(parent)
{
m_bufSize = bufSize4;m_buffer1 = new const char[m_bufSize]; m_buffer2 = new const char[m_bufSize]; m_rightOffset = 0; m_leftOffset = 0; m_cursor = 0; qMemSet((void *)m_buffer1,0,m_bufSize); }
//----------------------------------------------------------------------------------------------------------------------------------
~AudioBuffer()
{
delete m_buffer1;
delete m_buffer2;
}
//----------------------------------------------------------------------------------------------------------------------------------
void start()
{
if(!isOpen())
open(QIODevice::ReadWrite);
}
//----------------------------------------------------------------------------------------------------------------------------------
void stop()
{
close();
}
//----------------------------------------------------------------------------------------------------------------------------------
qint64 readData(char * data, qint64 len)
{
int free2end = m_bufSize-m_cursor;if(len <= free2end){ qMemCopy(data,m_buffer1+m_cursor,len); m_rightOffset += len; m_cursor += len; return len; } else { qMemCopy(data,m_buffer1+m_cursor,free2end); m_cursor = 0; qMemCopy(data+free2end,m_buffer1,len-free2end); m_rightOffset = len-free2end; m_leftOffset = 0; m_cursor += m_rightOffset; return len; } return 0; }
//----------------------------------------------------------------------------------------------------------------------------------
qint64 writeData(const char *data, qint64 len)
{
int free2end = m_bufSize-m_rightOffset;if(len <= free2end) // if we don't reach end of buffer { qMemCopy((void*)(m_buffer1+m_rightOffset),data,len); m_rightOffset += len; qDebug() << m_buffer1; return len; } else if(len <= (m_leftOffset+free2end)) { qMemCopy((void*)(m_buffer1+m_rightOffset),data,free2end); //write to end m_leftOffset = len-free2end; // need to write more from source and set new left offset qMemCopy((void*)m_buffer1,data+free2end,m_leftOffset); //write lefted part m_rightOffset = m_leftOffset; // set new right offset value m_leftOffset = 0; // set new left offset value qDebug() << m_buffer1; return len; } else { qMemCopy((void*)(m_buffer1+m_rightOffset),data,free2end); //write to end m_rightOffset += len-free2end; // need to write more from source len -= free2end; qMemCopy((void*)m_buffer1,data+free2end,m_leftOffset); //write lefted part m_rightOffset = 0; // set new right offset value len -= m_leftOffset; m_leftOffset = 0; qDebug() << m_buffer1; return len; } return 0; }
//----------------------------------------------------------------------------------------------------------------------------------
private:
const char * m_buffer1;
const char * m_buffer2;
int m_rightOffset;
int m_leftOffset;
int m_cursor;
int m_bufSize;
};#endif//AUDIOBUFFER_H@
And now I'm using it like this:
@m_output->start(m_buf);@
and it enters write data functions, but doesn't reads data. So question: How QAudioOutput asks for the data to play from QIODevice ? Is it call readData function or not ? And one more question: Is it possible to play rtsp stream using Phonon ? -
Interesting thing: when I play 22050 Hz 16 bit 2 channels audio stream - it plays normally without interruptions, but when playing 44100 Hz 16 bit stereo - not. If I open same stream(44 kHz) in VLC player or any other it plays normally without interruptions.