mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 940707 - Get more accurate latency numbers when using OpenSL. r=sotaro,kinetik
This dlopen libmedia.so, fetches some symbols and use that to determine the output latency of the stream. This also includes some fixes to get the minimal latency on Android 4.0.4, and makes the latency a bit better.
This commit is contained in:
parent
60083d6518
commit
2c7b0bb860
@ -33,6 +33,7 @@ struct cubeb {
|
||||
|
||||
#define NELEMS(A) (sizeof(A) / sizeof A[0])
|
||||
#define NBUFS 4
|
||||
#define AUDIO_STREAM_TYPE_MUSIC 3
|
||||
|
||||
struct cubeb_stream {
|
||||
cubeb * context;
|
||||
@ -45,6 +46,7 @@ struct cubeb_stream {
|
||||
long bytespersec;
|
||||
long framesize;
|
||||
int draining;
|
||||
cubeb_stream_type stream_type;
|
||||
|
||||
cubeb_data_callback data_callback;
|
||||
cubeb_state_callback state_callback;
|
||||
@ -224,18 +226,16 @@ opensl_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
|
||||
}
|
||||
|
||||
static int
|
||||
opensl_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms)
|
||||
opensl_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
|
||||
{
|
||||
/* https://android.googlesource.com/platform/ndk.git/+/master/docs/opensles/index.html
|
||||
* We don't want to deal with JNI here (and we don't have Java on b2g anyways),
|
||||
* so we just dlopen the library and get the two symbols we need. */
|
||||
|
||||
int rv;
|
||||
void * libmedia;
|
||||
uint32_t (*get_primary_output_samplingrate)(void);
|
||||
size_t (*get_primary_output_frame_count)(void);
|
||||
uint32_t (*get_primary_output_samplingrate)();
|
||||
uint32_t (*get_output_samplingrate)(int * samplingRate, int streamType);
|
||||
uint32_t primary_sampling_rate;
|
||||
size_t primary_buffer_size;
|
||||
|
||||
libmedia = dlopen("libmedia.so", RTLD_LAZY);
|
||||
if (!libmedia) {
|
||||
@ -246,29 +246,31 @@ opensl_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten
|
||||
get_primary_output_samplingrate =
|
||||
dlsym(libmedia, "_ZN7android11AudioSystem28getPrimaryOutputSamplingRateEv");
|
||||
if (!get_primary_output_samplingrate) {
|
||||
dlclose(libmedia);
|
||||
return CUBEB_ERROR;
|
||||
/* fallback to
|
||||
* status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType)
|
||||
* if we cannot find getPrimaryOutputSamplingRate. */
|
||||
get_output_samplingrate =
|
||||
dlsym(libmedia, "_ZN7android11AudioSystem21getOutputSamplingRateEPj19audio_stream_type_t");
|
||||
if (!get_output_samplingrate) {
|
||||
/* Another signature exists, with a int instead of an audio_stream_type_t */
|
||||
get_output_samplingrate =
|
||||
dlsym(libmedia, "_ZN7android11AudioSystem21getOutputSamplingRateEPii");
|
||||
if (!get_output_samplingrate) {
|
||||
dlclose(libmedia);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* size_t AudioSystem::getPrimaryOutputFrameCount(void) */
|
||||
get_primary_output_frame_count =
|
||||
dlsym(libmedia, "_ZN7android11AudioSystem26getPrimaryOutputFrameCountEv");
|
||||
if (!get_primary_output_frame_count) {
|
||||
dlclose(libmedia);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
primary_sampling_rate = get_primary_output_samplingrate();
|
||||
primary_buffer_size = get_primary_output_frame_count();
|
||||
|
||||
/* To get a fast track in Android's mixer, we need to be at the native
|
||||
* samplerate, which is device dependant. Some devices might be able to
|
||||
* resample when playing a fast track, but it's pretty rare. */
|
||||
if (primary_sampling_rate != params.rate) {
|
||||
/* If we don't know what to use, let's say 4 * 20ms buffers will do. */
|
||||
*latency_ms = NBUFS * 20;
|
||||
if (get_primary_output_samplingrate) {
|
||||
*rate = get_primary_output_samplingrate();
|
||||
} else {
|
||||
*latency_ms = NBUFS * primary_buffer_size / (primary_sampling_rate / 1000);
|
||||
/* We don't really know about the type, here, so we just pass music. */
|
||||
rv = get_output_samplingrate((int *) rate, AUDIO_STREAM_TYPE_MUSIC);
|
||||
if (rv) {
|
||||
dlclose(libmedia);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
dlclose(libmedia);
|
||||
@ -277,37 +279,63 @@ opensl_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten
|
||||
}
|
||||
|
||||
static int
|
||||
opensl_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
|
||||
opensl_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms)
|
||||
{
|
||||
/* https://android.googlesource.com/platform/ndk.git/+/master/docs/opensles/index.html
|
||||
* We don't want to deal with JNI here (and we don't have Java on b2g anyways,
|
||||
* We don't want to deal with JNI here (and we don't have Java on b2g anyways),
|
||||
* so we just dlopen the library and get the two symbols we need. */
|
||||
|
||||
int rv;
|
||||
void * libmedia;
|
||||
uint32_t (*get_primary_output_samplingrate)();
|
||||
size_t (*get_primary_output_frame_count)(void);
|
||||
int (*get_output_frame_count)(int * frameCount, int streamType);
|
||||
uint32_t primary_sampling_rate;
|
||||
size_t primary_buffer_size;
|
||||
|
||||
rv = opensl_get_preferred_sample_rate(ctx, &primary_sampling_rate);
|
||||
|
||||
if (rv) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
libmedia = dlopen("libmedia.so", RTLD_LAZY);
|
||||
if (!libmedia) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
/* uint32_t AudioSystem::getPrimaryOutputSamplingRate(void) */
|
||||
get_primary_output_samplingrate =
|
||||
dlsym(libmedia, "_ZN7android11AudioSystem28getPrimaryOutputSamplingRateEv");
|
||||
if (!get_primary_output_samplingrate) {
|
||||
dlclose(libmedia);
|
||||
return CUBEB_ERROR;
|
||||
/* JB variant */
|
||||
/* size_t AudioSystem::getPrimaryOutputFrameCount(void) */
|
||||
get_primary_output_frame_count =
|
||||
dlsym(libmedia, "_ZN7android11AudioSystem26getPrimaryOutputFrameCountEv");
|
||||
if (!get_primary_output_frame_count) {
|
||||
/* ICS variant */
|
||||
/* status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType) */
|
||||
get_output_frame_count =
|
||||
dlsym(libmedia, "_ZN7android11AudioSystem19getOutputFrameCountEPii");
|
||||
if (!get_output_frame_count) {
|
||||
dlclose(libmedia);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
*rate = get_primary_output_samplingrate();
|
||||
if (get_primary_output_frame_count) {
|
||||
primary_buffer_size = get_primary_output_frame_count();
|
||||
} else {
|
||||
if (get_output_frame_count(&primary_buffer_size, params.stream_type) != 0) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* To get a fast track in Android's mixer, we need to be at the native
|
||||
* samplerate, which is device dependant. Some devices might be able to
|
||||
* resample when playing a fast track, but it's pretty rare. */
|
||||
*latency_ms = NBUFS * primary_buffer_size / (primary_sampling_rate / 1000);
|
||||
|
||||
dlclose(libmedia);
|
||||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
opensl_destroy(cubeb * ctx)
|
||||
{
|
||||
@ -370,6 +398,7 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
|
||||
stm->state_callback = state_callback;
|
||||
stm->user_ptr = user_ptr;
|
||||
|
||||
stm->stream_type = stream_params.stream_type;
|
||||
stm->framesize = stream_params.channels * sizeof(int16_t);
|
||||
stm->bytespersec = stream_params.rate * stm->framesize;
|
||||
stm->queuebuf_len = (stm->bytespersec * latency) / (1000 * NBUFS);
|
||||
@ -504,7 +533,54 @@ opensl_stream_get_position(cubeb_stream * stm, uint64_t * position)
|
||||
int
|
||||
opensl_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
|
||||
{
|
||||
*latency = NBUFS * stm->queuebuf_len;
|
||||
int rv;
|
||||
void * libmedia;
|
||||
int32_t (*get_output_latency)(uint32_t * latency, int stream_type);
|
||||
uint32_t mixer_latency;
|
||||
uint32_t samplerate;
|
||||
|
||||
/* The latency returned by AudioFlinger is in ms, so we have to get
|
||||
* AudioFlinger's samplerate to convert it to frames. */
|
||||
rv = opensl_get_preferred_sample_rate(stm->context, &samplerate);
|
||||
if (rv) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
libmedia = dlopen("libmedia.so", RTLD_LAZY);
|
||||
if (!libmedia) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
/* Get the latency, in ms, from AudioFlinger */
|
||||
/* status_t AudioSystem::getOutputLatency(uint32_t* latency,
|
||||
* audio_stream_type_t streamType) */
|
||||
/* First, try the most recent signature. */
|
||||
get_output_latency =
|
||||
dlsym(libmedia, "_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t");
|
||||
if (!get_output_latency) {
|
||||
/* in case of failure, try the legacy version. */
|
||||
/* status_t AudioSystem::getOutputLatency(uint32_t* latency,
|
||||
* int streamType) */
|
||||
get_output_latency =
|
||||
dlsym(libmedia, "_ZN7android11AudioSystem16getOutputLatencyEPji");
|
||||
if (!get_output_latency) {
|
||||
dlclose(libmedia);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* audio_stream_type_t is an int, so this is okay. */
|
||||
rv = get_output_latency(&mixer_latency, stm->stream_type);
|
||||
|
||||
if (rv) {
|
||||
dlclose(libmedia);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
*latency = NBUFS * stm->queuebuf_len / stm->framesize + // OpenSL latency
|
||||
mixer_latency * samplerate / 1000; // AudioFlinger latency
|
||||
|
||||
dlclose(libmedia);
|
||||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user