Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Send raw data to QAudioOutput.
Forum Updated to NodeBB v4.3 + New Features

Send raw data to QAudioOutput.

Scheduled Pinned Locked Moved General and Desktop
21 Posts 4 Posters 15.3k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    Anticross
    wrote on last edited by
    #1

    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.

    1 Reply Last reply
    0
    • A Offline
      A Offline
      Anticross
      wrote on last edited by
      #2

      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

      1 Reply Last reply
      0
      • A Offline
        A Offline
        Anticross
        wrote on last edited by
        #3

        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.

        1 Reply Last reply
        0
        • A Offline
          A Offline
          Anticross
          wrote on last edited by
          #4

          It seems like data sending through RTP is converted to BigEndian format before reaching client. But I find no BigEndian support of playback, so maybe I need to do some fast conversation. Question: How to do that ?

          1 Reply Last reply
          0
          • T Offline
            T Offline
            tobias.hunger
            wrote on last edited by
            #5

            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.

            1 Reply Last reply
            0
            • A Offline
              A Offline
              Anticross
              wrote on last edited by
              #6

              OK, thanks. Another question: I have @unsigned char const* data@ with size @unsigned dataSize@ , qFromBigEndian needs to chose type (qInt16,qInt32,qInt64), and returns value of it's type, but how can I put this data back into unsigned char const* array with size of dataSize ?

              1 Reply Last reply
              0
              • A Offline
                A Offline
                Anticross
                wrote on last edited by
                #7

                This does not helped:
                @
                char * dt = new char[dataSize];
                itoa(qFromBigEndian<qint16>(data),dt,2);
                m_buf->writeData((const char*)dt,dataSize);
                delete dt;
                @

                1 Reply Last reply
                0
                • A Offline
                  A Offline
                  Anticross
                  wrote on last edited by
                  #8

                  Edited to :
                  @qint16 val = qFromBigEndian<qint16>(data);
                  uchar* dt = new uchar[dataSize];
                  qToLittleEndian<qint16>(val,dt);
                  m_buf->writeData((const char*)dt,dataSize);
                  delete dt;@
                  But the quality of audio is worse then without conversation.

                  1 Reply Last reply
                  0
                  • A Offline
                    A Offline
                    Anticross
                    wrote on last edited by
                    #9

                    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.

                    1 Reply Last reply
                    0
                    • A Offline
                      A Offline
                      Anticross
                      wrote on last edited by
                      #10

                      I open VLC player and receive this stream normally, then I look at codec details and see some PCM S16BE(twos). So what is it and can I transform data to play normal PCM on QAudioOutput ? So is it 16-bit Big-endian pcm or something else? What means S ?

                      1 Reply Last reply
                      0
                      • A Offline
                        A Offline
                        Anticross
                        wrote on last edited by
                        #11

                        I record output of my sound card when receiving stream with sine of 1000 Hz. After opening it in Sound Forge I see pauses in this sine with delays from 5 ms to 25 ms but sine has the same shape(I mean no distortions).

                        1 Reply Last reply
                        0
                        • T Offline
                          T Offline
                          tobias.hunger
                          wrote on last edited by
                          #12

                          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?

                          1 Reply Last reply
                          0
                          • A Offline
                            A Offline
                            Anticross
                            wrote on last edited by
                            #13

                            You're right the name must be at least nBytes :) Maybe QAudioOutput reads the buffer faster than it writes by receiving data from network, and I just need to wait some time before playing.

                            1 Reply Last reply
                            0
                            • A Offline
                              A Offline
                              Anticross
                              wrote on last edited by
                              #14

                              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_OBJECT

                              public:
                              //----------------------------------------------------------------------------------------------------------------------------------
                              AudioBuffer(/const QAudioFormat &format,/ QObject parent = NULL, int bufSize = 1400) : QIODevice(parent)
                              {
                              m_bufSize = bufSize
                              4;

                                  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 ?

                              1 Reply Last reply
                              0
                              • A Offline
                                A Offline
                                Anticross
                                wrote on last edited by
                                #15

                                One more question whats the main difference between push and pull mode of playing ?

                                1 Reply Last reply
                                0
                                • A Offline
                                  A Offline
                                  Anticross
                                  wrote on last edited by
                                  #16

                                  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.

                                  1 Reply Last reply
                                  0
                                  • B Offline
                                    B Offline
                                    billconan
                                    wrote on last edited by
                                    #17

                                    this is an interesting thread. a QAudioOuput from a buffer example should be added to the document.

                                    too bad the document only has an example of playing a file.

                                    1 Reply Last reply
                                    0
                                    • B Offline
                                      B Offline
                                      billconan
                                      wrote on last edited by
                                      #18

                                      has this issue been resolved yet? I also need to achieve the same thing?

                                      1 Reply Last reply
                                      0
                                      • B Offline
                                        B Offline
                                        billconan
                                        wrote on last edited by
                                        #19

                                        has this issue been resolved yet? I also need to achieve the same thing?

                                        1 Reply Last reply
                                        0
                                        • L Offline
                                          L Offline
                                          lynic
                                          wrote on last edited by
                                          #20

                                          I had a similar problem using a ringbuffer as a QIODevice backend for which I spent a whole day. The solution was to override the following method:

                                          @bool isSequential() const
                                          {
                                          return true;
                                          }@

                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved