66#include <portaudio.h>
77#include "rtmixer.h"
88
9+ static const struct stats EMPTY_STATS ;
10+
911#ifdef NDEBUG
1012#define CALLBACK_ASSERT (expr ) ((void)(0))
1113#else
@@ -78,6 +80,27 @@ frame_t seconds2samples(PaTime time, double samplerate)
7880 return (frame_t ) llround (time * samplerate );
7981}
8082
83+ PaTime get_relevant_time (const struct action * action
84+ , const PaStreamCallbackTimeInfo * timeInfo )
85+ {
86+ enum actiontype type = action -> type ;
87+ if (type == FETCH_AND_RESET_STATS )
88+ {
89+ return timeInfo -> currentTime ;
90+ }
91+ if (type == CANCEL )
92+ {
93+ CALLBACK_ASSERT (action -> action );
94+ type = action -> action -> type ;
95+ }
96+ if (type == PLAY_BUFFER || type == PLAY_RINGBUFFER )
97+ {
98+ return timeInfo -> outputBufferDacTime ;
99+ }
100+ CALLBACK_ASSERT (type == RECORD_BUFFER || type == RECORD_RINGBUFFER );
101+ return timeInfo -> inputBufferAdcTime ;
102+ }
103+
81104int callback (const void * input , void * output , frame_t frameCount
82105 , const PaStreamCallbackTimeInfo * timeInfo , PaStreamCallbackFlags statusFlags
83106 , void * userData )
@@ -96,16 +119,7 @@ int callback(const void* input, void* output, frame_t frameCount
96119 {
97120 struct action * const action = * actionaddr ;
98121
99- enum actiontype type = action -> type ;
100- if (type == CANCEL )
101- {
102- CALLBACK_ASSERT (action -> action );
103- type = action -> action -> type ;
104- }
105- const bool playing = type == PLAY_BUFFER || type == PLAY_RINGBUFFER ;
106-
107- PaTime io_time = playing ? timeInfo -> outputBufferDacTime
108- : timeInfo -> inputBufferAdcTime ;
122+ PaTime time = get_relevant_time (action , timeInfo );
109123 frame_t offset = 0 ;
110124
111125 // Check if the action is due to start in the current block
@@ -114,7 +128,7 @@ int callback(const void* input, void* output, frame_t frameCount
114128 {
115129 // This action has not yet been "active"
116130
117- PaTime diff = action -> requested_time - io_time ;
131+ PaTime diff = action -> requested_time - time ;
118132 if (diff >= 0.0 )
119133 {
120134 offset = seconds2samples (diff , state -> samplerate );
@@ -129,7 +143,7 @@ int callback(const void* input, void* output, frame_t frameCount
129143 continue ;
130144 }
131145 // Re-calculate "diff" to propagate rounding errors
132- action -> actual_time = io_time + (double )offset / state -> samplerate ;
146+ action -> actual_time = time + (double )offset / state -> samplerate ;
133147 }
134148 else
135149 {
@@ -140,7 +154,7 @@ int callback(const void* input, void* output, frame_t frameCount
140154 remove_action (actionaddr , state );
141155 continue ;
142156 }
143- action -> actual_time = io_time ;
157+ action -> actual_time = time ;
144158 }
145159 }
146160
@@ -161,7 +175,7 @@ int callback(const void* input, void* output, frame_t frameCount
161175 // delinquent is not yet playing/recording
162176
163177 frame_t delinquent_offset = 0 ;
164- PaTime diff = delinquent -> requested_time - io_time ;
178+ PaTime diff = delinquent -> requested_time - time ;
165179 if (diff >= 0.0 )
166180 {
167181 delinquent_offset = seconds2samples (diff , state -> samplerate );
@@ -217,6 +231,16 @@ int callback(const void* input, void* output, frame_t frameCount
217231 continue ;
218232 }
219233
234+ // Handle FETCH_AND_RESET_STATS action
235+
236+ if (action -> type == FETCH_AND_RESET_STATS )
237+ {
238+ action -> stats = state -> stats ;
239+ state -> stats = EMPTY_STATS ;
240+ remove_action (actionaddr , state );
241+ continue ;
242+ }
243+
220244 // Store buffer over-/underflow information
221245
222246 get_stats (statusFlags , & (action -> stats ));
@@ -238,9 +262,17 @@ int callback(const void* input, void* output, frame_t frameCount
238262
239263 // Shove audio data around
240264
241- float * device_data
242- = playing ? (float * )output + offset * state -> output_channels
243- : (float * ) input + offset * state -> input_channels ;
265+ float * device_data = NULL ;
266+ if (action -> type == PLAY_BUFFER || action -> type == PLAY_RINGBUFFER )
267+ {
268+ device_data = (float * )output + offset * state -> output_channels ;
269+ }
270+ else
271+ {
272+ CALLBACK_ASSERT (action -> type == RECORD_BUFFER
273+ || action -> type == RECORD_RINGBUFFER );
274+ device_data = (float * ) input + offset * state -> input_channels ;
275+ }
244276
245277 if (action -> type == PLAY_BUFFER || action -> type == RECORD_BUFFER )
246278 {
0 commit comments