audio_timing.h 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. #pragma once
  2. #include <stdbool.h>
  3. #include <stddef.h>
  4. #include <stdint.h>
  5. #include "audio_buffer.h"
  6. #include "audio_receiver.h"
  7. #include "audio_stream.h"
  8. typedef struct {
  9. uint32_t output_latency_us;
  10. uint32_t target_buffer_frames;
  11. uint32_t nominal_frame_samples;
  12. bool playout_started;
  13. bool playing;
  14. bool anchor_valid;
  15. uint64_t anchor_network_time_ns;
  16. uint32_t anchor_rtp_time;
  17. int64_t anchor_local_time_ns;
  18. int64_t ready_time_us; // When buffer became ready (0 = not ready yet)
  19. bool ptp_locked;
  20. uint8_t *pending_frame;
  21. size_t pending_frame_len;
  22. size_t pending_frame_capacity;
  23. bool pending_valid;
  24. // Early-frame guard: counts consecutive early frames to detect a stuck
  25. // anchor. Reset whenever a new anchor is set or a late/on-time frame is
  26. // played.
  27. int consecutive_early_frames;
  28. // Late-frame guard: counts consecutive individually-late frames. When this
  29. // Quick-start flag: set after a seek/flush/track-change so that
  30. // audio_timing_read starts playback with just 1 buffered frame instead of
  31. // waiting for target_buffer_frames. Anchor-based timing is used from the
  32. // very first frame (no bypass) — early frames are held as pending and
  33. // silence is output until their scheduled play time, exactly like
  34. // shairport-sync. Cleared once playout_started becomes true.
  35. bool quick_start;
  36. // Deferred flush (AirPlay 2 FLUSHBUFFERED with flushFromSeq present):
  37. // keep playing until a frame with rtp_timestamp >= flush_until_ts arrives,
  38. // then bulk-flush and start fresh. Written by the RTSP task, read by the
  39. // DMA callback task. Aligned 32-bit + bool — atomic on Xtensa without a
  40. // mutex (write flush_until_ts first, arm bool second; read bool first).
  41. bool deferred_flush_pending;
  42. uint32_t flush_until_ts;
  43. } audio_timing_t;
  44. void audio_timing_init(audio_timing_t *timing, size_t pending_capacity);
  45. void audio_timing_reset(audio_timing_t *timing);
  46. void audio_timing_set_format(audio_timing_t *timing,
  47. const audio_format_t *format);
  48. void audio_timing_set_output_latency(audio_timing_t *timing,
  49. const audio_format_t *format,
  50. uint32_t latency_us);
  51. uint32_t audio_timing_get_output_latency(const audio_timing_t *timing);
  52. uint32_t audio_timing_get_hardware_latency(void);
  53. // Total advertised latency (output + HW + fixed pipeline processing).
  54. // Use this for outputLatencyMicros, NOT (output + HW) alone — otherwise the
  55. // phone schedules sends 15 ms tight and the fill controller will pad
  56. // silence to compensate for the missing decode/decrypt/net delay.
  57. uint32_t audio_timing_get_advertised_latency(const audio_timing_t *timing);
  58. void audio_timing_set_anchor(audio_timing_t *timing,
  59. const audio_format_t *format, uint64_t clock_id,
  60. uint64_t network_time_ns, uint32_t rtp_time);
  61. void audio_timing_set_playing(audio_timing_t *timing, bool playing);
  62. size_t audio_timing_read(audio_timing_t *timing, audio_buffer_t *buffer,
  63. const audio_stream_t *stream, audio_stats_t *stats,
  64. int16_t *out, size_t samples);