Skip to content

Commit d215f63

Browse files
committed
ALSA: usb-audio: Check available frames for the next packet size
This is yet more preparation for the upcoming changes. Extend snd_usb_endpoint_next_packet_size() to check the available frames and return -EAGAIN if the next packet size is equal or exceeds the given size. This will be needed for avoiding XRUN during the low latency operation. As of this patch, avail=0 is passed, i.e. the check is skipped and no behavior change. Link: https://lore.kernel.org/r/20210929080844.11583-7-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent bceee75 commit d215f63

File tree

3 files changed

+39
-17
lines changed

3 files changed

+39
-17
lines changed

sound/usb/endpoint.c

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -148,18 +148,23 @@ int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep)
148148
* This won't be used for implicit feedback which takes the packet size
149149
* returned from the sync source
150150
*/
151-
static int slave_next_packet_size(struct snd_usb_endpoint *ep)
151+
static int slave_next_packet_size(struct snd_usb_endpoint *ep,
152+
unsigned int avail)
152153
{
153154
unsigned long flags;
155+
unsigned int phase;
154156
int ret;
155157

156158
if (ep->fill_max)
157159
return ep->maxframesize;
158160

159161
spin_lock_irqsave(&ep->lock, flags);
160-
ep->phase = (ep->phase & 0xffff)
161-
+ (ep->freqm << ep->datainterval);
162-
ret = min(ep->phase >> 16, ep->maxframesize);
162+
phase = (ep->phase & 0xffff) + (ep->freqm << ep->datainterval);
163+
ret = min(phase >> 16, ep->maxframesize);
164+
if (avail && ret >= avail)
165+
ret = -EAGAIN;
166+
else
167+
ep->phase = phase;
163168
spin_unlock_irqrestore(&ep->lock, flags);
164169

165170
return ret;
@@ -169,37 +174,53 @@ static int slave_next_packet_size(struct snd_usb_endpoint *ep)
169174
* Return the number of samples to be sent in the next packet
170175
* for adaptive and synchronous endpoints
171176
*/
172-
static int next_packet_size(struct snd_usb_endpoint *ep)
177+
static int next_packet_size(struct snd_usb_endpoint *ep, unsigned int avail)
173178
{
179+
unsigned int sample_accum;
174180
int ret;
175181

176182
if (ep->fill_max)
177183
return ep->maxframesize;
178184

179-
ep->sample_accum += ep->sample_rem;
180-
if (ep->sample_accum >= ep->pps) {
181-
ep->sample_accum -= ep->pps;
185+
sample_accum += ep->sample_rem;
186+
if (sample_accum >= ep->pps) {
187+
sample_accum -= ep->pps;
182188
ret = ep->packsize[1];
183189
} else {
184190
ret = ep->packsize[0];
185191
}
192+
if (avail && ret >= avail)
193+
ret = -EAGAIN;
194+
else
195+
ep->sample_accum = sample_accum;
186196

187197
return ret;
188198
}
189199

190200
/*
191201
* snd_usb_endpoint_next_packet_size: Return the number of samples to be sent
192202
* in the next packet
203+
*
204+
* If the size is equal or exceeds @avail, don't proceed but return -EAGAIN
205+
* Exception: @avail = 0 for skipping the check.
193206
*/
194207
int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep,
195-
struct snd_urb_ctx *ctx, int idx)
208+
struct snd_urb_ctx *ctx, int idx,
209+
unsigned int avail)
196210
{
197-
if (ctx->packet_size[idx])
198-
return ctx->packet_size[idx];
199-
else if (ep->sync_source)
200-
return slave_next_packet_size(ep);
211+
unsigned int packet;
212+
213+
packet = ctx->packet_size[idx];
214+
if (packet) {
215+
if (avail && packet >= avail)
216+
return -EAGAIN;
217+
return packet;
218+
}
219+
220+
if (ep->sync_source)
221+
return slave_next_packet_size(ep, avail);
201222
else
202-
return next_packet_size(ep);
223+
return next_packet_size(ep, avail);
203224
}
204225

205226
static void call_retire_callback(struct snd_usb_endpoint *ep,
@@ -263,7 +284,7 @@ static void prepare_silent_urb(struct snd_usb_endpoint *ep,
263284
unsigned int length;
264285
int counts;
265286

266-
counts = snd_usb_endpoint_next_packet_size(ep, ctx, i);
287+
counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, 0);
267288
length = counts * ep->stride; /* number of silent bytes */
268289
offset = offs * ep->stride + extra * i;
269290
urb->iso_frame_desc[i].offset = offset;

sound/usb/endpoint.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ void snd_usb_endpoint_free_all(struct snd_usb_audio *chip);
4646

4747
int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep);
4848
int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep,
49-
struct snd_urb_ctx *ctx, int idx);
49+
struct snd_urb_ctx *ctx, int idx,
50+
unsigned int avail);
5051

5152
#endif /* __USBAUDIO_ENDPOINT_H */

sound/usb/pcm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,7 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
13651365
spin_lock_irqsave(&subs->lock, flags);
13661366
subs->frame_limit += ep->max_urb_frames;
13671367
for (i = 0; i < ctx->packets; i++) {
1368-
counts = snd_usb_endpoint_next_packet_size(ep, ctx, i);
1368+
counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, 0);
13691369
/* set up descriptor */
13701370
urb->iso_frame_desc[i].offset = frames * stride;
13711371
urb->iso_frame_desc[i].length = counts * stride;

0 commit comments

Comments
 (0)