A noteworthy Qt6 issue: QIODevice::readAll() create by QAudioSource returns an odd byte length for qint16 sample points.
-
When I migrated a Qt5 project to Qt6, I ran into this problem. Under Windows 10, My instances of MSYS2 Qt 6.2.0 x64 compilation are not working properly. I traced the debugging and found the problem.
My old code presupposes that readAll must return a complete sample.
//QAudioSource *AudioInputSound = new QAudioSource(dev, format, this); //QIODevice InputDev = AudioInputSound->start(); //connect(InputDev, SIGNAL(readyRead()), SLOT(OnReadMore())); void Dialog::OnReadMore() { //... QByteArray data = InputDev->readAll(); const short * spt = (const short * ) data.constData(); //Audio sample point size will be 4 bytes for stereo, 2 bytes for mono. const int point_size = sizeof(short) * channels; //Problem Here it is! //This Operation suppose that (data.size() % point_size ==0). int points = data.size()/point_size; //Do signal process funtions. deal_function(spt, point_size, points); //When funtion returns, data will be recycled. The lost of odd tail disrupts subsequent samples. }
But under the new Qt6, it returns an odd number of bytes. This is an issue that I didn't think through. Currently, it is solved by a cache that preserves the tail data.
//... QByteArray buffer; void Dialog::OnReadMore() { //We can put bytes to a buffer first. buffer.append(InputDev->readAll()); const short * spt = (const short * ) buffer.constData(); const int point_size = sizeof(short) * channels; //The variable "points" now refers to the maximum number of samples that can be processed. int points = buffer.size()/point_size; deal_function(spt, point_size, points); //Remove old data and KEEP the tail. buffer.remove(0,points* point_size); }
This introduces some performance issues. However, it is not a big problem for low-speed devices such as sound cards.
This is not a BUG, but this behavior of the QAudioInput module can be troubling. Some poorly designed programs crash, just like mine. For Qt, which may be used in medical devices, special attention needs to be paid to this feature.
I wish Qt better and better!
-
@goldenhawking
I admit I know nothing about QAudioSource, butQIODevice::readAll()
has never promised to read "all the data there will be", it has only ever said it will read "whatever data is currently available to it from the device", and there may well be future calls of "readyRead()" which will see further data till all has been consumed. We frequently have to remind coders here of this when they write TCP/IP/socket code and fail to take this into account. Maybe you have been "lucky" relying on the behaviour you observed in Qt5-. -
As @JonB already told you - it's a stream, there is no such thing like a 'packet' in a stream. You ave to take care of a higher level protocol by your own.
It worked by accident for you until now. -
That's it~ Programming is a rigorous job, but debugging brings joy !
-
@JonB @Christian Ehrlicher Thanks for your suggestions! I've worked around this issue and fixed up 3 possible errors in different projects. It's lucky that error code still works in Qt5, and patches can be silently applied in-time.
-
@goldenhawking said in A noteworthy Qt6 issue: QIODevice::readAll() create by QAudioSource returns an odd byte length for qint16 sample points.:
It's lucky that error code still works in Qt5
I think so, yes, you just happened to be getting away with it!
Suppose Qt6 is actually faster than Qt5 (unlikely!). The
readyRead()
/readAll()
could just happen to be called earlier than it used to be, so that the complete audio data had not yet been received.