1919 }} while (false)
2020#endif
2121
22- void remove_action (struct action * * addr , struct state * state )
22+ void remove_action (struct action * * addr , const struct state * state )
2323{
2424 struct action * action = * addr ;
2525 * addr = action -> next ; // Current action is removed from list
@@ -43,6 +43,11 @@ void get_stats(PaStreamCallbackFlags flags, struct stats* stats)
4343 if (flags & paOutputOverflow ) { stats -> output_overflows ++ ; }
4444}
4545
46+ frame_t seconds2samples (PaTime time , double samplerate )
47+ {
48+ return (frame_t ) llround (time * samplerate );
49+ }
50+
4651int callback (const void * input , void * output , frame_t frameCount
4752 , const PaStreamCallbackTimeInfo * timeInfo , PaStreamCallbackFlags statusFlags
4853 , void * userData )
@@ -82,21 +87,23 @@ int callback(const void* input, void* output, frame_t frameCount
8287 }
8388 const bool playing = type == PLAY_BUFFER || type == PLAY_RINGBUFFER ;
8489
85- // Check if the action is due to start in the current block
86-
8790 PaTime io_time = playing ? timeInfo -> outputBufferDacTime
8891 : timeInfo -> inputBufferAdcTime ;
8992 frame_t offset = 0 ;
9093
94+ // Check if the action is due to start in the current block
95+
9196 if (action -> done_frames == 0 )
9297 {
98+ // This action has not yet been "active"
99+
93100 PaTime diff = action -> requested_time - io_time ;
94101 if (diff >= 0.0 )
95102 {
96- offset = ( frame_t ) llround ( diff * state -> samplerate );
103+ offset = seconds2samples ( diff , state -> samplerate );
97104 if (offset >= frameCount )
98105 {
99- // We are too early!
106+ // We are too early, let's continue in the next block !
100107
101108 // Due to inaccuracies in timeInfo, "diff" might have a small negative
102109 // value in a future block. We don't count this as "belated" though:
@@ -124,25 +131,69 @@ int callback(const void* input, void* output, frame_t frameCount
124131
125132 if (action -> type == CANCEL )
126133 {
134+ // Search the following list items, not the preceding ones!
127135 for (struct action * * i = & (action -> next ); * i ; i = & ((* i )-> next ))
128136 {
129137 if (* i == action -> action )
130138 {
131139 struct action * delinquent = * i ;
132140
133- if (delinquent -> done_frames + offset > delinquent -> total_frames )
141+ if (delinquent -> done_frames == 0 )
134142 {
135- // TODO: stops on its own ... set some error state?
143+ // delinquent is not yet playing/recording
144+
145+ frame_t delinquent_offset = 0 ;
146+ PaTime diff = delinquent -> requested_time - io_time ;
147+ if (diff >= 0.0 )
148+ {
149+ delinquent_offset = seconds2samples (diff , state -> samplerate );
150+ if (delinquent_offset >= offset )
151+ {
152+ // Removal is scheduled before playback/recording begins
153+
154+ // TODO: save some status information?
155+ remove_action (i , state );
156+ break ;
157+ }
158+ }
159+ else
160+ {
161+ if (!delinquent -> allow_belated )
162+ {
163+ // TODO: save some status information?
164+ break ; // The action will not be started, no need to cancel it
165+ }
166+ }
167+
168+ if (delinquent -> total_frames + delinquent_offset > offset )
169+ {
170+ CALLBACK_ASSERT (offset >= delinquent_offset );
171+ delinquent -> total_frames = offset - delinquent_offset ;
172+ }
173+ else
174+ {
175+ // TODO: stops on its own ... save some status information?
176+ }
136177 }
137178 else
138179 {
139- delinquent -> total_frames = delinquent -> done_frames + offset ;
180+ CALLBACK_ASSERT (
181+ delinquent -> total_frames >= delinquent -> done_frames );
182+ if (delinquent -> total_frames - delinquent -> done_frames > offset )
183+ {
184+ delinquent -> total_frames = delinquent -> done_frames + offset ;
185+ }
186+ else
187+ {
188+ // TODO: stops on its own ... save some status information?
189+ }
140190 }
141191 // TODO: save some informations to action->...?
142- break ;
192+
193+ break ; // We found the action, no need to keep searching
143194 }
144195 }
145- // TODO: what if the action to cancel wasn't found? set actual_time = 0.0?
196+ // TODO: what if the action to cancel wasn't found?
146197
147198 remove_action (actionaddr , state ); // Remove the CANCEL action itself
148199 continue ;
0 commit comments