【发布时间】:2013-06-10 13:15:34
【问题描述】:
我正在编写一个简单的 NDK OpenSL ES 音频应用程序,该应用程序记录用户在虚拟钢琴键盘上的触摸,然后在设定的循环中永久播放它们。经过大量的实验和阅读,我决定使用单独的 POSIX 循环来实现这一点。正如您在代码中看到的,它从睡眠时间中减去任何处理时间,以使每个循环的间隔尽可能接近所需的睡眠间隔(在本例中为 5000000 纳秒。
void init_timing_loop() {
pthread_t fade_in;
pthread_create(&fade_in, NULL, timing_loop, (void*)NULL);
}
void* timing_loop(void* args) {
while (1) {
clock_gettime(CLOCK_MONOTONIC, &timing.start_time_s);
tic_counter(); // simple logic gates that cycle the current tic
play_all_parts(); // for-loops through all parts and plays any notes (From an OpenSL buffer) that fall on the current tic
clock_gettime(CLOCK_MONOTONIC, &timing.finish_time_s);
timing.diff_time_s.tv_nsec = (5000000 - (timing.finish_time_s.tv_nsec - timing.start_time_s.tv_nsec));
nanosleep(&timing.diff_time_s, NULL);
}
return NULL;
}
问题是即使使用它,结果也会更好,但相当不一致。有时音符会一次延迟甚至 50 毫秒,这会导致播放非常不稳定。
有没有更好的方法来解决这个问题?为了调试,我运行了以下代码:
gettimeofday(&timing.curr_time, &timing.tzp);
__android_log_print(ANDROID_LOG_DEBUG, "timing_loop", "gettimeofday: %d %d",
timing.curr_time.tv_sec, timing.curr_time.tv_usec);
这给出了相当一致的读数 - 这并不反映播放不准确。 Android 是否还有其他因素在阻止准确计时?还是 OpenSL ES 是一个潜在的问题?所有缓冲区数据都加载到内存中 - 那里可能存在瓶颈吗?
如果需要,很高兴发布更多 OpenSL 代码......但在这个阶段,我正在尝试确定这个线程循环是否准确,或者是否有更好的方法。
【问题讨论】:
-
一个想法:始终保持音频缓冲区满。通过“播放”适当数量的静音样本来填充静音。这样,一切都通过音频时钟计时,可变延迟不会影响您(只要您保持缓冲区满)。
-
感谢您的回复,这似乎是一个更好的方法。具有基于缓冲区的计时的问题是:对于复音,我需要一次加载多达 16 个缓冲区队列。如果我一直让它们充满 - 你认为它们会保持同步吗?无论如何我都会给它一个测试,但我想我会问你是否有这样做的经验。
-
标签: android c android-ndk opensl