Я пишу простое аудиоприложение 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, если это необходимо... но на данном этапе я пытаюсь выяснить, является ли этот цикл потока точным или есть лучший способ сделать это.