Skip to content

Commit f8e79b3

Browse files
committed
Take care of some "cancel" edge cases
1 parent 6d195e0 commit f8e79b3

1 file changed

Lines changed: 61 additions & 10 deletions

File tree

src/rtmixer.c

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
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+
4651
int 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

Comments
 (0)