使用NDK准确的POSIX线程计时

时间:2013-06-14 00:01:53

标签: android c android-ndk opensl

我正在编写一个简单的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代码......但是在这个阶段我正在尝试弄清楚这个线程循环是否准确或者是否有更好的方法来实现它。

1 个答案:

答案 0 :(得分:0)

使用clock_gettime时你应该考虑几秒钟,你可能比timing.start_time_s.tv_nsec更大timing.finish_time_s.tv_nsec。当tv_nsec增加时,tv_sec从零开始。

timing.diff_time_s.tv_nsec =
(5000000 - (timing.finish_time_s.tv_nsec - timing.start_time_s.tv_nsec));

尝试类似

的内容
#define NS_IN_SEC 1000000000
(timing.finish_time_s.tv_sec * NS_IN_SEC + timing.finish_time_s.tv_nsec) -
(timing.start_time_s.tv_nsec * NS_IN_SEC + timing.start_time_s.tv_nsec)