mirror of https://github.com/encounter/SDL.git
Work around hang in AAudioStream_write() during extended shared object loading while running in a debugger. Observed on a OnePlus 8T (KB2005) running Oxygen OS 11.0.10.10.KB05AA.
The observed behavior is that any nonzero timeout value would hang until the device was paused and resumed. And a zero timeout value would always return 0 frames written even when audio fragments could be heard. Making a manual timeout system unworkable. None of the straightforward systems imply that there's a detectable problem before the call to AAudioStream_write(). And the callback set within AAudioStreamBuilder_setErrorCallback() does not get called as we enter the hang state. I've found that AAudioStream_getTimestamp() will report an error state from another thread. So this change codifies that behavior a bit until a better fix or more root cause can be found.
This commit is contained in:
parent
325ae5c35d
commit
2423c51471
|
@ -62,6 +62,12 @@ static int aaudio_LoadFunctions(AAUDIO_Data *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void aaudio_errorCallback( AAudioStream *stream, void *userData, aaudio_result_t error );
|
||||
void aaudio_errorCallback( AAudioStream *stream, void *userData, aaudio_result_t error )
|
||||
{
|
||||
LOGI( "SDL aaudio_errorCallback: %d - %s", error, ctx.AAudio_convertResultToText( error ) );
|
||||
}
|
||||
|
||||
#define LIB_AAUDIO_SO "libaaudio.so"
|
||||
|
||||
static int
|
||||
|
@ -109,6 +115,8 @@ aaudio_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
ctx.AAudioStreamBuilder_setFormat(ctx.builder, format);
|
||||
}
|
||||
|
||||
ctx.AAudioStreamBuilder_setErrorCallback( ctx.builder, aaudio_errorCallback, private );
|
||||
|
||||
LOGI("AAudio Try to open %u hz %u bit chan %u %s samples %u",
|
||||
this->spec.freq, SDL_AUDIO_BITSIZE(this->spec.format),
|
||||
this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
|
||||
|
@ -412,6 +420,33 @@ void aaudio_ResumeDevices(void)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
We can sometimes get into a state where AAudioStream_write() will just block forever until we pause and unpause.
|
||||
None of the standard state queries indicate any problem in my testing. And the error callback doesn't actually get called.
|
||||
But, AAudioStream_getTimestamp() does return AAUDIO_ERROR_INVALID_STATE
|
||||
*/
|
||||
SDL_bool aaudio_DetectBrokenPlayState( void )
|
||||
{
|
||||
if ( !audioDevice || !audioDevice->hidden ) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
struct SDL_PrivateAudioData *private = audioDevice->hidden;
|
||||
|
||||
int64_t framePosition, timeNanoseconds;
|
||||
aaudio_result_t res = ctx.AAudioStream_getTimestamp( private->stream, CLOCK_MONOTONIC, &framePosition, &timeNanoseconds );
|
||||
if ( res == AAUDIO_ERROR_INVALID_STATE ) {
|
||||
aaudio_stream_state_t currentState = ctx.AAudioStream_getState( private->stream );
|
||||
/* AAudioStream_getTimestamp() will also return AAUDIO_ERROR_INVALID_STATE while the stream is still initially starting. But we only care if it silently went invalid while playing. */
|
||||
if ( currentState == AAUDIO_STREAM_STATE_STARTED ) {
|
||||
LOGI( "SDL aaudio_DetectBrokenPlayState: detected invalid audio device state: AAudioStream_getTimestamp result=%d, framePosition=%lld, timeNanoseconds=%lld, getState=%d", (int)res, (long long)framePosition, (long long)timeNanoseconds, (int)currentState );
|
||||
return SDL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
#endif /* SDL_AUDIO_DRIVER_AAUDIO */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -44,6 +44,7 @@ struct SDL_PrivateAudioData
|
|||
|
||||
void aaudio_ResumeDevices(void);
|
||||
void aaudio_PauseDevices(void);
|
||||
SDL_bool aaudio_DetectBrokenPlayState(void);
|
||||
|
||||
|
||||
#endif /* _SDL_aaudio_h */
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#define SDL_PROC_UNUSED(ret,func,params)
|
||||
|
||||
SDL_PROC(const char *, AAudio_convertResultToText, (aaudio_result_t returnCode))
|
||||
SDL_PROC_UNUSED(const char *, AAudio_convertStreamStateToText, (aaudio_stream_state_t state))
|
||||
SDL_PROC(const char *, AAudio_convertStreamStateToText, (aaudio_stream_state_t state))
|
||||
SDL_PROC(aaudio_result_t, AAudio_createStreamBuilder, (AAudioStreamBuilder** builder))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setDeviceId, (AAudioStreamBuilder* builder, int32_t deviceId))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setSampleRate, (AAudioStreamBuilder* builder, int32_t sampleRate))
|
||||
|
@ -41,7 +41,7 @@ SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSessionId, (AAudioStreamBuilder* bu
|
|||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setPrivacySensitive, (AAudioStreamBuilder* builder, bool privacySensitive)) /* API 30 */
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setDataCallback, (AAudioStreamBuilder* builder, AAudioStream_dataCallback callback, void *userData))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setFramesPerDataCallback, (AAudioStreamBuilder* builder, int32_t numFrames))
|
||||
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setErrorCallback, (AAudioStreamBuilder* builder, AAudioStream_errorCallback callback, void *userData))
|
||||
SDL_PROC(void, AAudioStreamBuilder_setErrorCallback, (AAudioStreamBuilder* builder, AAudioStream_errorCallback callback, void *userData))
|
||||
SDL_PROC(aaudio_result_t , AAudioStreamBuilder_openStream, (AAudioStreamBuilder* builder, AAudioStream** stream))
|
||||
SDL_PROC(aaudio_result_t , AAudioStreamBuilder_delete, (AAudioStreamBuilder* builder))
|
||||
SDL_PROC_UNUSED(aaudio_result_t , AAudioStream_release, (AAudioStream* stream)) /* API 30 */
|
||||
|
@ -50,7 +50,7 @@ SDL_PROC(aaudio_result_t , AAudioStream_requestStart, (AAudioStream* stream))
|
|||
SDL_PROC(aaudio_result_t , AAudioStream_requestPause, (AAudioStream* stream))
|
||||
SDL_PROC_UNUSED(aaudio_result_t , AAudioStream_requestFlush, (AAudioStream* stream))
|
||||
SDL_PROC(aaudio_result_t , AAudioStream_requestStop, (AAudioStream* stream))
|
||||
SDL_PROC_UNUSED(aaudio_stream_state_t, AAudioStream_getState, (AAudioStream* stream))
|
||||
SDL_PROC(aaudio_stream_state_t, AAudioStream_getState, (AAudioStream* stream))
|
||||
SDL_PROC_UNUSED(aaudio_result_t, AAudioStream_waitForStateChange, (AAudioStream* stream, aaudio_stream_state_t inputState, aaudio_stream_state_t *nextState, int64_t timeoutNanoseconds))
|
||||
SDL_PROC(aaudio_result_t, AAudioStream_read, (AAudioStream* stream, void *buffer, int32_t numFrames, int64_t timeoutNanoseconds))
|
||||
SDL_PROC(aaudio_result_t, AAudioStream_write, (AAudioStream* stream, const void *buffer, int32_t numFrames, int64_t timeoutNanoseconds))
|
||||
|
@ -71,7 +71,7 @@ SDL_PROC_UNUSED(aaudio_direction_t, AAudioStream_getDirection, (AAudioStream* st
|
|||
SDL_PROC_UNUSED(int64_t, AAudioStream_getFramesWritten, (AAudioStream* stream))
|
||||
SDL_PROC_UNUSED(int64_t, AAudioStream_getFramesRead, (AAudioStream* stream))
|
||||
SDL_PROC_UNUSED(aaudio_session_id_t, AAudioStream_getSessionId, (AAudioStream* stream)) /* API 28 */
|
||||
SDL_PROC_UNUSED(aaudio_result_t, AAudioStream_getTimestamp, (AAudioStream* stream, clockid_t clockid, int64_t *framePosition, int64_t *timeNanoseconds))
|
||||
SDL_PROC(aaudio_result_t, AAudioStream_getTimestamp, (AAudioStream* stream, clockid_t clockid, int64_t *framePosition, int64_t *timeNanoseconds))
|
||||
SDL_PROC_UNUSED(aaudio_usage_t, AAudioStream_getUsage, (AAudioStream* stream)) /* API 28 */
|
||||
SDL_PROC_UNUSED(aaudio_content_type_t, AAudioStream_getContentType, (AAudioStream* stream)) /* API 28 */
|
||||
SDL_PROC_UNUSED(aaudio_input_preset_t, AAudioStream_getInputPreset, (AAudioStream* stream)) /* API 28 */
|
||||
|
|
|
@ -51,9 +51,11 @@ static void openslES_PauseDevices(void) {}
|
|||
#if !SDL_AUDIO_DISABLED && SDL_AUDIO_DRIVER_AAUDIO
|
||||
extern void aaudio_ResumeDevices(void);
|
||||
extern void aaudio_PauseDevices(void);
|
||||
SDL_bool aaudio_DetectBrokenPlayState( void );
|
||||
#else
|
||||
static void aaudio_ResumeDevices(void) {}
|
||||
static void aaudio_PauseDevices(void) {}
|
||||
static SDL_bool aaudio_DetectBrokenPlayState( void ) { return SDL_FALSE; }
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -168,6 +170,11 @@ Android_PumpEvents_Blocking(_THIS)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( aaudio_DetectBrokenPlayState() ) {
|
||||
aaudio_PauseDevices();
|
||||
aaudio_ResumeDevices();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -246,6 +253,11 @@ Android_PumpEvents_NonBlocking(_THIS)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( aaudio_DetectBrokenPlayState() ) {
|
||||
aaudio_PauseDevices();
|
||||
aaudio_ResumeDevices();
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_ANDROID */
|
||||
|
|
Loading…
Reference in New Issue