Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QIODevice::writeData is not triggered when working with with 64 channels QAuioFormat



  • I want to use a custom QIODevice to process audio data received from Soundflower (64 channel). I noticed the QIODevice::writeData function is only triggered if I manually change QAudioFormat's channelCount to anything less than 16. How can I make it work with soundflower's original audioformat, which is 64 channel? Or is this a bug in the QIODevice? Here is the sample codes:

    void MyWidget::deviceChanged (const QAudioDeviceInfo &device)
    {
        if (m_audioInput)
        {
            m_audioInput->stop();
            delete m_audioInput;
        }
    
        if (m_streamReader)
        {
            m_streamReader->stop();
            delete m_streamReader;
        }
    
        QAudioFormat format = device.preferredFormat();
    
        // this line shows the original format: QAudioFormat(44100Hz, 32bit, channelCount=64, sampleType=SignedInt, byteOrder=BigEndian, codec="audio/pcm")
        qDebug() << "original format:" << format;
    
        // in order to make QIODevice::writeData(const char *data, qint64 len) being triggered, I need to manually set the channel count to anything less than 16, if the channel count is more than 15, the QIODevice:writeData won't be triggered
        format.setChannelCount(8);
        m_audioInput = new QAudioInput(device, format);
        // StreamReader is a subclass of QIODevice
        m_streamReader = new StreamReader(m_audioInput->format(), this);
        m_streamReader->start();
        m_audioInput->start(m_streamReader);
        qDebug() << m_audioInput->state();
    }
    
    // here is the function of QIODevice subclass that doesn't work as expected
    qint64 StreamReader::writeData(const char *data, qint64 len)
    {
        // this function is called only if audioFormat.channelCount is <=16
    }
    

    When the channelCount is set to 64, the AudioInput state is StoppedState, but if I hard-code the channelCount to anything <= 16, the state is IdleState


  • Qt Champions 2019

    @Thinium said in QIODevice::writeData is not triggered when working with with 64 channels QAuioFormat:

    MyQIODevice* streamReader = new StreamReader(m_audioInput->format(), this);

    What do you expect from this line (except maybe a memleak)?



  • @Christian-Ehrlicher thanks for the reply! I just updated the question to reflect the actual code. StreamReader is a member of myWidget and it has a function that receives audio signal from the selected audio device (in my case Soundflower 64 channels)

    qint64 StreamReader::writeData(const char *data, qint64 len)
    

  • Qt Champions 2019

    But why would a reader and an input would call write()?

    btw: still leaks when deviceChanged() more than once.



  • @Christian-Ehrlicher yes I am aware this would leak. I didn't add the delete codes just to show the core of the issue.

    According to the documentation, AudioInput "Writes" to the QIODevice. For more info:
    https://doc.qt.io/qt-5/qaudioinput.html#start
    Starts transferring audio data from the system's audio input to the device. The device must have been opened in the WriteOnly, Append or ReadWrite modes.



  • @Thinium
    Wow, I think it is hard to know bacause I don't have a 64-channel device on Windows. :(
    BTW, what's the bufferSize after start?

    @Christian-Ehrlicher
    The internal process of an audio input is that, it reads data from the audio device, then write that data to the user provided device.



  • @Bonnie thanks for the reply! It fails when you manually set the channelCount to anything more than 16 channels. You don't really need a real device to reproduce that.

    The buffer size after start is 4096, no matter what my channel settings are. Here are the buffer size for 2channels and 64channels:

    "Soundflower (2ch)"
    QAudioFormat(44100Hz, 32bit, channelCount=2, sampleType=SignedInt, byteOrder=BigEndian, codec="audio/pcm")
    IdleState
    buffersize 4096

    "Soundflower (64ch)"
    QAudioFormat(44100Hz, 32bit, channelCount=64, sampleType=SignedInt, byteOrder=BigEndian, codec="audio/pcm")
    StoppedState
    buffersize 4096

    As you can see, when AudioFormat is set to 64ch, the QAudioInput is in stopped state. Which I don't understand why.


  • Qt Champions 2019

    @Bonnie said in QIODevice::writeData is not triggered when working with with 64 channels QAuioFormat:

    then write that data to the user provided device.

    So at least the class name is wrong (it's a StreamWriter, not StreamReader).



  • @Thinium Seems there's an open error. You can check the m_audioInput->error() result.
    Does device.isFormatSupported(m_audioInput->format()) returns true in 64ch mode?



  • @Bonnie indeed the format is not supported! That's surely why the audioInput can't be started.



  • @Thinium I found this in the source code (coreaudiodeviceinfo.mm)

    QList<int> CoreAudioDeviceInfo::supportedChannelCounts()
        {
            static QList<int> supportedChannels;
        
            if (supportedChannels.isEmpty()) {
                // If the number of channels is not supported by an audio device, Core Audio will
                // automatically convert the audio data.
                for (int i = 1; i <= 16; ++i)
                    supportedChannels.append(i);
            }
        
            return supportedChannels;
        }
    

    So Qt will only allow 1~16 channels.


Log in to reply