即使在设置了设备的首选采样率和缓冲区后,我也遇到了噼啪声/有故障的音频问题(基本上是缓冲区未填满/回调未及时完成/缓冲区欠载情况)使用 OpenSL ES 时的大小。
我已经在 Nexus 7(2013 型号)和 Moto X Pure Edition 上进行了测试,它们都运行良好(分别使用 48 kHz 的采样率和 240 和 960 的缓冲区大小)。也许每分钟左右都会出现一个小故障,但我已经接受了它。但是,当我使用三星 Galaxy S7 时,我每秒都会遇到大量音频故障(这也是在 48 kHz 和每个缓冲区 960 帧时)。我检查过,音频回调总是在正确的时间(20 毫秒)内完成;因此我可以说没有缓冲区欠载。
奇怪的问题是,如果我将三星设置为使用 44.1 kHz 的采样率和 128 的缓冲区大小,则不会出现音频故障(除了一个小中断,我猜它处理的是不正确的 native 采样率) .
为什么会发生这种情况,我该如何解决才能使 native 音频属性正常工作?
谢谢!
编辑:也许我混淆了术语(缓冲区欠载和溢出)所以如果有人想进来纠正我,请继续吧!学习就是力量
最佳答案
我不确定您如何能够根据您的目的调整它,但我是这样做的:
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()。如果缓冲区正在播放,则函数退出。
祈祷这对您有所帮助。
关于Android OpenSL Audio Buffer underrun with native sample rate/buffer size(仅限某些设备),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40116514/