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 minimise audio output latency?
Forum Updated to NodeBB v4.3 + New Features

How to minimise audio output latency?

Scheduled Pinned Locked Moved Unsolved General and Desktop
7 Posts 4 Posters 1.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.
  • T Offline
    T Offline
    ThomH
    wrote on last edited by
    #1

    I'm porting an emulator to Qt. So I have programmatically-generated audio, and I want only a limited amount of forward buffering.

    As a first attempt I tried push audio, grabbing a QIODevice and writing to it as and when data is available. I am testing under macOS and have called setBufferSize with a small number before calling start (though I'm suspicious that it doesn't work; see below), but latency is still noticeably dreadful. I had the idea that maybe I'm allowing too much audio to become buffered during initial startup, but there's no obvious way to determine how much data is currently buffered so there's no way to compensate for that at runtime.

    So I switched to implementing my own QIODevice and using the QAudioOutput pull interface. I figured that gives me sufficient control to avoid over-buffering. But then the interface appears to act illogically. In my specific case, I call setBufferSize with a value of 1024. I then start the output. I query bufferSize() and get a value of 2048. Fine, not great, but fine. Except that the buffer size appears to have no bearing on the QIODevice calls — the QAudioOutput always requests buffers in 16384-byte chunks despite the buffer size being 2048.

    I guess this cuts to the documentation offering no definition for what the buffer size actually means, but I definitely can't come up with any meaningful interpretation in which a buffer which advertises itself as being 2048 bytes would then attempt to read data in 16384-byte chunks.

    As an aside, my machine's output rate is 48,000 Hz and as a result that's the output rate I'm requesting (via QAudioDeviceInfo::defaultOutputDevice().preferredFormat(), but manually verified as being 48,000 on my particular machine). Given that I'm requesting 16-bit audio, 1/6th of a second's latency could well be what I'm hearing, though it feels a lot longer.

    So:

    • what does the buffer size actually mean, given that a value of 2048 is reported by an audio output that pulls data in 16384-byte chunks?
    • is there something I'm supposed to do other than call setBufferSize to request the lowest latency that Qt can provide?

    As an aside, the native macOS version of this app works without disturbance with buffers as small as 512 bytes. So I don't think that either my machine or my OS is causing a problem.

    Also, I'm aware that using some other library for the relatively specialised purpose of low-latency audio wouldn't necessarily be a bad idea, but I also want a working pure-Qt build, that does the best that Qt can do.

    1 Reply Last reply
    0
    • B Offline
      B Offline
      Bonnie
      wrote on last edited by Bonnie
      #2

      Hello, I've just looked into that problem not long time ago.
      The key point is, when opening the io device, remember to add QIODevice::Unbuffered to OpenMode, or it will always ask at least 16384 bytes, which is hardcoded in qiodevice_p.h:

      #ifndef QIODEVICE_BUFFERSIZE
      #define QIODEVICE_BUFFERSIZE 16384
      #endif
      
      1 Reply Last reply
      3
      • T Offline
        T Offline
        ThomH
        wrote on last edited by
        #3

        Fantastic, thanks!

        That seems to make the QAudioOutput act much closer to what I'd expect given its bufferSize(); it still announces a size of 2048 but now seems primarily to read in 1024-byte increments.

        It's a shame that there isn't an exact meaning of buffer size — empirically on macOS I guess it's a ring buffer that is filled half at a time — but I guess if I take it to be 'the maximum amount that may be read at a time' then I have more than enough information to obtain that minimum available latency, and provide the absolute best plain-Qt experience that I can.

        Thanks again!

        Pablo J. RoginaP 1 Reply Last reply
        0
        • T ThomH

          Fantastic, thanks!

          That seems to make the QAudioOutput act much closer to what I'd expect given its bufferSize(); it still announces a size of 2048 but now seems primarily to read in 1024-byte increments.

          It's a shame that there isn't an exact meaning of buffer size — empirically on macOS I guess it's a ring buffer that is filled half at a time — but I guess if I take it to be 'the maximum amount that may be read at a time' then I have more than enough information to obtain that minimum available latency, and provide the absolute best plain-Qt experience that I can.

          Thanks again!

          Pablo J. RoginaP Offline
          Pablo J. RoginaP Offline
          Pablo J. Rogina
          wrote on last edited by
          #4

          @ThomH could your issue be called as solved? Thanks.

          Upvote the answer(s) that helped you solve the issue
          Use "Topic Tools" button to mark your post as Solved
          Add screenshots via postimage.org
          Don't ask support requests via chat/PM. Please use the forum so others can benefit from the solution in the future

          1 Reply Last reply
          0
          • M Offline
            M Offline
            Mr.FreshDachs
            wrote on last edited by
            #5

            Hey guys!

            Sorry to dig up this old thread, but I am currently at the exact same position as OP, the QAudioOutput always requests chunks of 16384 Byte-Data in pull-operation, which is quite too much to achieve low latency.
            If I open my self implemented QIODevice in" QIODevice::Unbuffered" instead of "QIODevice:: readOnly" as Bonnie suggested I am getting a warning "Devie is opened in write-only mode" and the Audio Output wont even start. Is there someting I am missing?
            I am using the audiodevice_out->open(QIODevice::Unbuffered) function.
            Can I somehow add the 'unbuffered' property to the readOnly-Mode?

            I'd be really grateful if you could anwser me!

            Kind regards!

            B 1 Reply Last reply
            0
            • M Mr.FreshDachs

              Hey guys!

              Sorry to dig up this old thread, but I am currently at the exact same position as OP, the QAudioOutput always requests chunks of 16384 Byte-Data in pull-operation, which is quite too much to achieve low latency.
              If I open my self implemented QIODevice in" QIODevice::Unbuffered" instead of "QIODevice:: readOnly" as Bonnie suggested I am getting a warning "Devie is opened in write-only mode" and the Audio Output wont even start. Is there someting I am missing?
              I am using the audiodevice_out->open(QIODevice::Unbuffered) function.
              Can I somehow add the 'unbuffered' property to the readOnly-Mode?

              I'd be really grateful if you could anwser me!

              Kind regards!

              B Offline
              B Offline
              Bonnie
              wrote on last edited by
              #6

              @Mr-FreshDachs
              You should add that flag to what you are using, not use it only, like QIODevice::ReadOnly | QIODevice::Unbuffered

              1 Reply Last reply
              5
              • M Offline
                M Offline
                Mr.FreshDachs
                wrote on last edited by
                #7

                Since I'm a real noob in Qt and pretty much C++ in general, I didn't even know you could do that!

                Now It's working just as expected.
                Thank you very much!

                1 Reply Last reply
                2

                • Login

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