Regarding the code I spot two minor things:
getDefaultDevice() should be directly after
getAvailableDevices(), and
getDevice() should be directly before/after
setDevice(). Then the initialisation of
m_deviceName could use
getDefaultDevice() instead of duplicating one line of code.
Regarding potential data races in this class, if we assume the user will use a recorder's API on one thread only (or on multiple thread but with a proper use of mutex), having in mind that all attributes are private, we can say the following:
- m_thread is only used by the user's thread so it's okay.
- m_samples is written in the user thread when start() is called, but then it's not read nor written from that thread. Only the worker thread use it and it is not exposed to subclass in a writable way so it's also okay.
- m_sampleRate follow the same schema. (*) so it's also okay.
- m_processingInterval is always writable from the user thread but is also read on the worker thread. There is a potential data race here but its impact is zero on the overall system – in the worst case the value is updated on the worker thread one loop iteration (in record()) later than expected. So it's also okay.
- m_deviceName is not read / write concurrently so it's okay too.
- Finally, the last attribute is m_isCapturing. It's mainly like m_processingInterval except for one irrelevant data race: both threads can write it to false at the same time if stop() is called when onProcessSamples() return false. So it's okay too.
However, there is an undocumented (I think) possible data race on
captureDevice /
alcCaptureOpenDevice() when
start() is called on two different recorders from two different threads. I haven't looked at the documentation of
alcCaptureOpenDevice() so I can only speculate that one of the two recorders will fail if the implementation of OpenAL is thread safe. Otherwise we could simply add in the documentation of
start() that this situation results in an undefined behaviour.
(*) it would be good I think to add in the documentation that
getSampleRate() is valid / meaningful only after
start() is called since it's not set by the user in the constructor of the class.
Let me know if you think my interpretation of the code is right, or wrong.