2016-10-18 3 views
0

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

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

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

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

Спасибо!

EDIT: Возможно, я смешиваю терминологию вверх (переполнение буфера и переполнение), поэтому, если кто-то хочет войти и исправить меня по этому поводу! обучение сила

+0

Вы используете обратный вызов для очереди новых буферов? – WLGfx

+0

@WLGfx Я уверен, что я это делаю (может быть, неправильно, я признаю, что мое понимание того, как все работает, нуждается в улучшении). Я использую этот класс для настройки обратного вызова и аудиопотока: https://github.com/superpoweredSDK/audioIO/blob/master/SuperpoweredAndroidAudioIO.cpp –

+0

Обратный вызов не вызывается после завершения буферов, только перед буфер вот-вот закончит давать вам шанс поставить в очередь другой. Вам придется вручную добавить еще одну очередь, а затем снова включить обратный вызов. Возможно, несмотря на то, что обратный вызов вызывается при очереди буфера, у вас недостаточно времени для подготовки другого. В моем проекте, каждое обновление экрана, я проверяю, играют ли sles, и если нет, я вручную добавляю в буфер еще один буфер. – WLGfx

ответ

0

Я не знаю, как вы были бы в состоянии приспособить это к своей цели, но вот как я это сделал:

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(). Если буферы воспроизводятся, функция выходит.

Пальцы, пересекшие это, помогут вам.

+0

Спасибо! Я сообщу вам, когда узнаю все! –