Files
pocketsphinx/examples/endpointer_timestamp_example.c
Kevin Lenzo 69185976d2 Add external timestamp support to endpointer to prevent clock drift
- Added ps_endpointer_timestamp_cb_t callback type for external timestamps
- Added ps_endpointer_set_timestamp_func() to set external timestamp source
- Added ps_endpointer_timestamp() to get current timestamp
- Modified internal timestamp handling to use callback when available
- Maintains full backward compatibility - existing code works unchanged
- Added comprehensive test suite (test_endpointer_timestamp)
- Added example program demonstrating the new functionality

This addresses issue #352 by allowing applications to provide their own
timestamp source (e.g., system time, monotonic clock) to avoid drift
between audio clock and system clock. The implementation maintains the
audio-based timestamp tracking internally for queue management while
using the external source for speech start/end timestamps when provided.
2025-07-16 15:21:00 -04:00

116 lines
3.2 KiB
C

/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
/**
* Example of using external timestamp sources with ps_endpointer_t
* to avoid timestamp drift between audio and system clocks.
*/
#include <stdio.h>
#include <time.h>
#ifdef __APPLE__
#include <sys/time.h>
#endif
#include <pocketsphinx.h>
/* Get system time in seconds (monotonic clock) */
static double
get_system_time(void *user_data)
{
struct timespec ts;
(void)user_data; /* unused */
#ifdef __APPLE__
/* macOS doesn't have clock_gettime before 10.12 */
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + tv.tv_usec / 1000000.0;
#else
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec + ts.tv_nsec / 1000000000.0;
#endif
}
int
main(int argc, char *argv[])
{
ps_endpointer_t *ep;
int16 frame[480]; /* Frame buffer - size determined by endpointer */
int frame_size;
double start_time;
int i;
(void)argc;
(void)argv;
/* Initialize endpointer with default settings */
ep = ps_endpointer_init(0, 0, PS_VAD_LOOSE, 16000, 0.0);
if (ep == NULL) {
fprintf(stderr, "Failed to initialize endpointer\n");
return 1;
}
frame_size = ps_endpointer_frame_size(ep);
printf("Endpointer frame size: %d samples\n", frame_size);
/* Set external timestamp callback to use system time */
if (ps_endpointer_set_timestamp_func(ep, get_system_time, NULL) < 0) {
fprintf(stderr, "Failed to set timestamp callback\n");
ps_endpointer_free(ep);
return 1;
}
start_time = get_system_time(NULL);
printf("Starting at system time: %.3f\n", start_time);
/* Simulate processing audio frames */
printf("\nProcessing frames with system timestamps:\n");
for (i = 0; i < 100; i++) {
const int16 *speech;
/* Generate dummy audio data (silence in this example) */
int j;
for (j = 0; j < frame_size; j++)
frame[j] = 0;
/* Process frame */
speech = ps_endpointer_process(ep, frame);
/* Every 10 frames, print timestamp */
if (i % 10 == 9) {
double current_time = ps_endpointer_timestamp(ep);
double elapsed = current_time - start_time;
printf("Frame %3d: System time: %.3f, Elapsed: %.3f sec\n",
i + 1, current_time, elapsed);
}
/* If speech is detected (won't happen with silence) */
if (speech != NULL) {
printf("Speech detected at: %.3f\n",
ps_endpointer_speech_start(ep));
}
}
/* Demonstrate reverting to audio timestamps */
printf("\nReverting to audio-based timestamps:\n");
ps_endpointer_set_timestamp_func(ep, NULL, NULL);
for (i = 0; i < 20; i++) {
const int16 *speech;
int j;
for (j = 0; j < frame_size; j++)
frame[j] = 0;
speech = ps_endpointer_process(ep, frame);
(void)speech; /* unused */
}
/* Audio timestamp continues from where it was */
printf("Audio timestamp after 20 more frames: %.3f\n",
ps_endpointer_timestamp(ep));
ps_endpointer_free(ep);
printf("\nExample completed successfully.\n");
return 0;
}