Android OpenSL Audio Buffer переполнен с собственной частотой дискретизации / размером буфера (только некоторые устройства)

Похоже, у меня проблема с потрескивающим / сбойным звуком (в основном, когда буфер не заполняется / обратный вызов не завершается во время / переполнение буфера) даже после установки предпочтительной частоты дискретизации устройства и размера буфера при использовании OpenSL ES.

Я тестировал Nexus 7 (модель 2013 года) и Moto X Pure Edition, и они оба работают нормально (с частотой дискретизации 48 кГц и размером буфера 240 и 960 соответственно). Может быть, что-то вроде сбоя каждую минуту или около того, но так мало, что я смирился с этим жить. Однако, когда я использую Samsung Galaxy S7, я получаю тонну глюков звука каждую секунду (это также при 48 кГц и 960 кадрах на буфер). Я проверил, и аудио обратный вызов всегда завершается в течение правильного времени (20 мс); поэтому могу сказать, что нет опустошения буфера.

Странная проблема заключается в том, что, если я настрою Samsung на использование частоты дискретизации 44,1 кГц и размера буфера 128, то нет никаких глюков звука (за исключением небольшого прерывания, которое, как я предполагаю, связано с неправильной собственной частотой дискретизации).

Почему это происходит и как я могу это исправить, чтобы нативные свойства звука работали?

Спасибо!

РЕДАКТИРОВАТЬ: Возможно, я смешиваю терминологию (переполнение буфера и переполнение), так что если кто-то захочет войти и исправить меня, продолжайте !!! обучение это сила

2

Решение

Я не уверен, как вы сможете адаптировать это к вашей цели, но вот как я это сделал:

Функция обратного вызова SLES:

void AudioManager::sles_callback(SLAndroidSimpleBufferQueueItf itf, void *ptr) {
AudioManager *manager = (AudioManager*)ptr;
manager->audio_queue_playing = false;
manager->check_audio_playback(); // the actual function to queue buffers
}

Проверка наличия другого аудио буфера:

void AudioManager::check_audio_playback() {
// mutex used to only allow one thread access at a time
pthread_mutex_lock(&audio_callback_mutex); // block access to renderer or callback

if (audio_queue_playing || playback_pos == decode_pos) {
pthread_mutex_unlock(&audio_callback_mutex);
return;
}

double audio_pts = pts_start_time;
double render_time = Display.get_current_render_time();

AudioBuffer *buffer = nullptr;

if (last_played_buffer) {
last_played_buffer->used = false;
buffer = &buffers[playback_pos];
//(*buffer_interface)->Enqueue(buffer_interface, buffer->data, (SLuint32)(buffer->nsamples << 2));
//audio_queue_playing = true;
last_played_buffer = buffer;
playback_pos = (++playback_pos) % MAX_AUD_BUFFERS;
//return;
}

if (audio_pts < 0.0) {
if (ffmpeg.vid_stream.stream_id == -1) {    // start playback
pts_start_time = buffers[playback_pos].frame_time;
audio_pts = pts_start_time;
sys_start_time = render_time;
}
}

AudioBuffer *temp = nullptr;

double current_time = render_time - sys_start_time;

bool bounds = false;
double temp_time;

while (!bounds) {
if (playback_pos == decode_pos) bounds = true;
else {
temp = &buffers[playback_pos];
temp_time = temp->frame_time - audio_pts;

if (temp_time < current_time) {
if (buffer) buffer->used = false;
buffer = temp;
playback_pos = (++playback_pos) % MAX_AUD_BUFFERS;
} else {
bounds = true;
}
}
}

if (buffer) {
audio_queue_playing = true;
(*buffer_interface)->Enqueue(buffer_interface, buffer->data, (SLuint32)(buffer->nsamples << 2));
last_played_buffer = buffer;
} else {
last_played_buffer = nullptr;
}

pthread_mutex_unlock(&audio_callback_mutex);
}

И затем при каждом обновлении кадра (т.е. в моем рендерере экрана 60 раз в секунду) я вызываю check_audio_playback (). Если воспроизводятся буферы, то функция завершается.

Скрещенные пальцы это поможет вам в этом.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]