繁体   English   中英

Android OpenSL音频缓冲区欠载,具有本机采样率/缓冲区大小(仅限部分设备)

[英]Android OpenSL Audio Buffer underrun with native sample rate/buffer size (only some devices)

看起来我遇到了一个噼啪声/故障音频问题(基本上当缓冲区没有被填满/回调没有在时间/缓冲区欠载情况下完成),即使在使用时设置了设备的首选采样率和缓冲区大小OpenSL ES。

我已经在Nexus 7(2013型号)和Moto X Pure Edition上进行了测试,它们都工作正常(使用48 kHz的采样率和240和960的缓冲区大小)。 也许每分钟左右就会出现一次小故障,但是我很少接受与它一起生活的问题。 但是,当我使用三星Galaxy S7时,我每秒都会收到大量的音频故障(这也是48 kHz和每个缓冲区960帧)。 我已经检查过,音频回调总是在正确的时间内完成(20毫秒); 因此我可以说没有缓冲区不足。

奇怪的问题是,如果我将三星设置为使用44.1 kHz的采样率和128的缓冲区大小,则不存在音频故障(除了我猜测的小中断处理不正确的本机采样率)。

为什么会发生这种情况,我该如何解决它以便原生音频属性有效?

谢谢!

编辑 :也许我正在混淆术语(缓冲区欠载和溢出),所以如果有人想进来并纠正我,请继续! 学习才是力量

我不确定你怎么能够根据你的目的调整它,但这就是我的方法:

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()。 如果正在播放缓冲区,则该函数退出。

越过这个手指将帮助你。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM