diff options
-rw-r--r-- | sound/usb/card.h | 2 | ||||
-rw-r--r-- | sound/usb/endpoint.c | 4 | ||||
-rw-r--r-- | sound/usb/pcm.c | 13 |
3 files changed, 17 insertions, 2 deletions
diff --git a/sound/usb/card.h b/sound/usb/card.h index 6c0a052a28f9..5b19901f305a 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -94,6 +94,7 @@ struct snd_usb_endpoint { struct list_head ready_playback_urbs; /* playback URB FIFO for implicit fb */ unsigned int nurbs; /* # urbs */ + unsigned int nominal_queue_size; /* total buffer sizes in URBs */ unsigned long active_mask; /* bitmask of active urbs */ unsigned long unlink_mask; /* bitmask of unlinked urbs */ char *syncbuf; /* sync buffer for all sync URBs */ @@ -187,6 +188,7 @@ struct snd_usb_substream { } dsd_dop; bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */ + bool early_playback_start; /* early start needed for playback? */ struct media_ctl *media_ctl; }; diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 8b1bec51c806..bf26c04cf471 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -1126,6 +1126,10 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep) INIT_LIST_HEAD(&u->ready_list); } + /* total buffer bytes of all URBs plus the next queue; + * referred in pcm.c + */ + ep->nominal_queue_size = maxsize * urb_packs * (ep->nurbs + 1); return 0; out_of_memory: diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 4e5031a68064..f5cbf61ac366 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -614,6 +614,14 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) subs->period_elapsed_pending = 0; runtime->delay = 0; + /* check whether early start is needed for playback stream */ + subs->early_playback_start = + subs->direction == SNDRV_PCM_STREAM_PLAYBACK && + subs->data_endpoint->nominal_queue_size >= subs->buffer_bytes; + + if (subs->early_playback_start) + ret = start_endpoints(subs); + unlock: snd_usb_unlock_shutdown(chip); return ret; @@ -1394,7 +1402,7 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, subs->trigger_tstamp_pending_update = false; } - if (period_elapsed && !subs->running) { + if (period_elapsed && !subs->running && !subs->early_playback_start) { subs->period_elapsed_pending = 1; period_elapsed = 0; } @@ -1448,7 +1456,8 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea prepare_playback_urb, retire_playback_urb, subs); - if (cmd == SNDRV_PCM_TRIGGER_START) { + if (!subs->early_playback_start && + cmd == SNDRV_PCM_TRIGGER_START) { err = start_endpoints(subs); if (err < 0) { snd_usb_endpoint_set_callback(subs->data_endpoint, |