We have a custom USoundWave
-derived asset which can potentially return 0 from GeneratePCMData
if it has not uncompressed the data in time. This tends to happen just the first couple of times after the asset is loaded. On Windows this does not cause any noticeable issue, but when deploying to Android it results in a crash.
Is it acceptable for this method to potentially return 0? Looking at the various implementations in the engine, it seems that it is.
Here’s what I’ve found from debugging:
FAudioDevice::StartSources
calls Source->Init
(AudioDevice.cpp:1943) to initialize a new source with the wave instance.
After a successful call to CreatePlayer()
, FSLESSoundSource::Init
sets the WaveInstance
member of the source to InWaveInstance
.
If the following Enqueue call fails* (see below), then DestroyPlayer()
is called, which nulls out the various SL_
interfaces on the source, then Init
returns false. Note that the WaveInstance
member of the source remains non-null.
WaveInstance->StopWithoutNotification()
is called (AudioDevice.cpp:1957).
In the next call of FAudioDevice::Update
, the sources are iterated through and IsFinished()
is called on each one (AudioDevice.cpp:2015).
This will call IsSourceFinished()
if the WaveInstance
member of the source is non-null (AndroidAudioSource.cpp:568). Even though our source failed to initialize, its WaveInstance
member retained a valid pointer.
FSLESSoundSource::IsSourceFinished
dereferences the SL_PlayerPlayInterface
interface pointer (AndroidAudioSource:549), which had been nulled out in DestroyPlayer
, resulting in a crash.
*I’m seeing the following in the log at this point:
05-16 22:27:26.784 7968 7992 W libOpenSLES: Leaving BufferQueue::Enqueue (SL_RESULT_PARAMETER_INVALID)
I suspect this is failing as a result of GeneratePCMData
returning 0, which is causing AudioBuffers[0].AudioDataSize
to be set to zero, and I’m guessing that is what is considered the invalid parameter. Regardless, I don’t think a failure here is intended to result in the crash that follows.