QAudioDecoder timing race
-
I'm using a QAudioDecoder (inside a C++ object accessed from QML) to read WAV files. If I set the sourceFilename when the user selects the file, and then start the reading when the user clicks a separate button, it works fine but with one problem: it opens the file when the sourceFilename is set, and leaves it open forever, or until I change the filename. If I want to create a new version of the WAV file in some other program, it is unable to update the file.
The "solution" is to set sourceFilename to a null string after reading the WAV file. That does indeed close the original file, but also means that I need to set sourceFilename just before calling start(). But if I do that, it doesn't work correctly because the file format is actually determined by another thread which hasn't run yet, so start() reuses the previous format set into the QAudioDecoder. When that other thread discovers the new format, and tries to set the audioFormat, the change is ignored because start() has already been called. If the old format is invalid, it emits an error.
So I tried moving the call to start() into a handler for the formatChanged signal. The problem is that that only gets called if the format is actually changed. I tried setting a default-constructed (invalid) QAudioFormat when the read is finished, to ensure that formatChanged will be emitted when a new file is selected, but that seems to be ignored if there is no longer a valid file associated with the QAudioDecoder.
So what do I do? As I investigate this, I'm becoming aware of how complicated Qt's method of reading a WAV file is, since it's part of a much larger, more general system for parsing a stream of data from any asynchronous source. I'm thinking it might be better to just write my own local file reader, since uncompressed PCM WAV files are pretty simple.
I've filed bug report 77741 on this.
-
@pderocco said in QAudioDecoder timing race:
I'm thinking it might be better to just write my own local file reader, since uncompressed PCM WAV files are pretty simple.
In your particular use case I agree.