+static size_t uaudio_play_samples(void *buffer, size_t samples, unsigned flags) {
+ static struct timespec base;
+ static int64_t frames_supplied;
+ struct timespec now;
+ struct timespec delay_ts;
+ double target, delay;
+
+ if(!base.tv_sec)
+ xgettime(CLOCK_MONOTONIC, &base);
+ samples = uaudio_thread_play_callback(buffer, samples, flags);
+ frames_supplied += samples / uaudio_channels;
+ /* Set target to the approximate point at which we run out of buffered audio.
+ * If no buffer size has been specified, use 1/16th of a second. */
+ target = (frames_supplied - (uaudio_buffer ? uaudio_buffer : uaudio_rate / 16))
+ / (double)uaudio_rate + ts_to_double(base);
+ for(;;) {
+ xgettime(CLOCK_MONOTONIC, &now);
+ delay = target - ts_to_double(now);
+ if(delay <= 0) {
+ //putc('.', stderr);
+ break;
+ }
+ //putc('!', stderr);
+ /*
+ fprintf(stderr, "frames supplied %ld (%lds) base %f target %f now %f want delay %g\n",
+ frames_supplied,
+ frames_supplied / uaudio_rate,
+ ts_to_double(base),
+ target,
+ ts_to_double(now),
+ delay);
+ */
+ delay_ts = double_to_ts(delay);
+ xnanosleep(&delay_ts, NULL);
+ }
+ return samples;
+}
+