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
-
@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)?
-
@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)
-
But why would a reader and an input would call write()?
btw: still leaks when deviceChanged() more than once.
-
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. -
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
@Thinium
Wow, I think it is hard to know bacause I don't have a 64-channel device on Windows. :(
BTW, what's thebufferSize
afterstart
?@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. -
@Thinium
Wow, I think it is hard to know bacause I don't have a 64-channel device on Windows. :(
BTW, what's thebufferSize
afterstart
?@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 4096As you can see, when AudioFormat is set to 64ch, the QAudioInput is in stopped state. Which I don't understand why.
-
@Thinium
Wow, I think it is hard to know bacause I don't have a 64-channel device on Windows. :(
BTW, what's thebufferSize
afterstart
?@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 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).
-
@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 4096As you can see, when AudioFormat is set to 64ch, the QAudioInput is in stopped state. Which I don't understand why.
-
@Thinium Seems there's an open error. You can check the
m_audioInput->error()
result.
Doesdevice.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.