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. How to record and play sound simultaneously
QtWS25 Last Chance

How to record and play sound simultaneously

Scheduled Pinned Locked Moved General and Desktop
13 Posts 3 Posters 10.2k Views
  • 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.
  • S Offline
    S Offline
    sayem.bd
    wrote on last edited by
    #1

    Hi, I wanted to know is there any way to record and play sound at the same time in Qt. I want to record sound from a microphone and at the same time I want to play it in the speaker/headphone.

    Is there any way to do this in Qt? Or do I need to use any other library?

    1 Reply Last reply
    0
    • S Offline
      S Offline
      sayem.bd
      wrote on last edited by
      #2

      This is what I have tried so far -

      @void AudioRecorder::on_btnStart_clicked()
      {
      // Get audio format and search for nearest matching format of the device
      QAudioFormat format = this->getFormat();

      // Star recording using the specified format
      this->audioInput = new QAudioInput(format, this);
      connect(this->audioInput,SIGNAL(stateChanged(QAudio::State)),
                                      SLOT(inputStateChanged(QAudio::State)));
      QIODevice *myBuffer = this->audioInput->start();
      
      this->audioOutput = new QAudioOutput(format, this);
      connect(this->audioOutput,SIGNAL(stateChanged(QAudio::State)), 
                                      SLOT(outputStateChanged(QAudio::State)));
      this->audioOutput->start(myBuffer);
      

      }

      QAudioFormat AudioRecorder::getFormat()
      {
      QAudioFormat format;
      format.setFrequency(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))
      {
          this->log("Default format not supported. Trying to use the nearest format.....");
          format = info.nearestFormat(format);
      }
      
      return format;
      

      }@

      This code works fine for some time after I start recording i.e., I talk in the microphone and I can hear my voice on the headphones, but after some time the audioOutput changes its state to IDLE because of UnderrunError, which according to "this":http://doc.qt.nokia.com/stable/qaudio.html#Error-enum documentation means -

      bq. Audio data is not being fed to the audio device at a fast enough rate

      What should I do to solve this problem?

      1 Reply Last reply
      0
      • V Offline
        V Offline
        vidar
        wrote on last edited by
        #3

        Yes, it is possible to record and output audio simultaneously in Qt. You might take a look at http://developer.qt.nokia.com/forums/viewthread/7679/ . However, I guess that (for Windows) the latency you can achieve with Qt is not the best...

        1 Reply Last reply
        0
        • V Offline
          V Offline
          vidar
          wrote on last edited by
          #4

          I wonder if it is possible to use a QIODevice directly, without subclassing it, as the documentation says:

          bq. QIODevice is abstract and can not be instantiated, but it is common to use the interface it defines to provide device-independent I/O features

          You might consider creating your own QIODevice subclass to implement fast read and write methods by using a circular buffer. I did that some time ago and never experienced underruns, even for high-quality settings (48000Hz etc.).
          Which OS are you using?

          1 Reply Last reply
          0
          • S Offline
            S Offline
            sayem.bd
            wrote on last edited by
            #5

            I am using Linux (Mint 11), but obviously I want it to run on all linux distros, and it would be really great if the solution also works on Mac and Windows.

            1 Reply Last reply
            0
            • S Offline
              S Offline
              sayem.bd
              wrote on last edited by
              #6

              [quote author="vidar" date="1318837148"]However, I guess that (for Windows) the latency you can achieve with Qt is not the best...[/quote]

              Then which library will give me the best latency and performance? I would really like to know. Is it cross-platform?

              1 Reply Last reply
              0
              • F Offline
                F Offline
                Franzk
                wrote on last edited by
                #7

                You generally need an ASIO sound card to get proper latency on windows. However, if you don't have an asio enabled sound card you can use "ASIO4ALL":http://www.asio4all.com, which has given decent results for me in the past on cheap hardware with applications like Cubase VST.

                "Horse sense is the thing a horse has which keeps it from betting on people." -- W.C. Fields

                http://www.catb.org/~esr/faqs/smart-questions.html

                1 Reply Last reply
                0
                • V Offline
                  V Offline
                  vidar
                  wrote on last edited by
                  #8

                  @Franzk: No, you don't need ASIO for lowest latency on Windows. WASAPI provides great latencies as well (in Exclusive Mode) and you don't need to cope with ASIO4ALL etc.

                  @sayem.bd: A library called "portaudio" will be the solution you want. It supports WASAPI and ASIO on Windows and also supports ALSA / Linux and MacOS stuff.
                  You can compile the portaudio to a library and use it in your Qt project.
                  "See":http://www.portaudio.com/

                  (P.S. If you use WASAPI, be sure to use the synchronous API functions, due to a Windows bug...)

                  1 Reply Last reply
                  0
                  • S Offline
                    S Offline
                    sayem.bd
                    wrote on last edited by
                    #9

                    I have sub-classed QIODevice and re-implemented the writeData and readData method. The code is given "here":http://pastebin.com/n7e9KREA. The problem is, I am still running into the Underrun error. I have applied a hack in these scenario, you can check it in the outputStateChanged method. Whenever I am running into idle state, I am forcefully starting it again. As a result, now my audio plays nicely, but I am not sure if this is recommended approach since I am simply swallowing an error.

                    Why am I still getting Underrun Error? Is there anything wrong in my QIODevice subclass implementation or is there any other mechanism?

                    Please note that my input and output both devices are using the same audio format.

                    1 Reply Last reply
                    0
                    • V Offline
                      V Offline
                      vidar
                      wrote on last edited by
                      #10

                      The code looks good and I assume that your MAXSIZE is large enough to buffer the latency between the start of the recording and the start of the output. Hmm, well ... Do the Qt audio demos work on your system? I guess your application does not perform any processing that might block the read/write methods?

                      ( Otherwise you could try out portaudio, which works fine with Qt projects. It's not that different from the audio API that Qt uses and it already handles that buffering stuff internally (though I must admit that its API appears to be more complex).
                      After you tried out some console applications using portaudio, you can try migrating your code into your Qt project by adding the portaudio library to the LIBS setting in your Qt project file. The portaudio part should maybe be done in a second thread.... )

                      1 Reply Last reply
                      0
                      • S Offline
                        S Offline
                        sayem.bd
                        wrote on last edited by
                        #11

                        I have run the Spectrum Analyzer example in my machine, and it's running nicely. I am not doing any extra processing that might block the read/write methods (I guess). This is a pretty simple GUI application which has a window and a button and after pressing that button I am initializing the audio input/output and calling the start methods on them (you can see it from the code that I have posted there).

                        However, I was debugging the code today, with breakpoints set to the first statements of both the writeData and readData methods and found that sometimes after a write has occured, two consecutive read is occurring. Suppose that writeData method wrote X bytes of data into the buffer. then immediately after that a read is occurring, reading those X bytes of data from the buffer. After this read, the currentBufferLength obviously turns to zero. After this read, another read is again happening before a write could occur. Since in the second read the buffer length is zero so the read method is simply returning zero from the first statement. I think this is the reason why the output device is running into the underrun error.

                        This event is totally random but is occurring frequently. I don't know what's the reason behind this and how to stop these random consecutive reads.

                        @vidar: Thanks for bearing with me this far, by the way :-) .

                        1 Reply Last reply
                        0
                        • V Offline
                          V Offline
                          vidar
                          wrote on last edited by
                          #12

                          Ok. Maybe try to use the "push" mode instead... Good luck ;-)

                          1 Reply Last reply
                          0
                          • S Offline
                            S Offline
                            sayem.bd
                            wrote on last edited by
                            #13

                            @vidar: If you are on stackoverflow, then you can post your answer there. I have asked this question there with a bounty of 100 reputations, and your answer is the one which helped me most. I think you deserve this bounty :-) .

                            The question can be found "here":http://stackoverflow.com/questions/7776022/.

                            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