• Takashi Iwai's avatar
    ALSA: usb-audio: Improved lowlatency playback support · d5f871f8
    Takashi Iwai authored
    This is another attempt to improve further the handling of playback
    stream in the low latency mode.  The latest workaround in commit
    4267c5a8 ("ALSA: usb-audio: Work around for XRUN with low latency
    playback") revealed that submitting URBs forcibly in advance may
    trigger XRUN easily.  In the classical mode, this problem was avoided
    by practically delaying the submission of the actual data with the
    pre-submissions of silent data before triggering the stream start.
    But that is exactly what we want to avoid.
    
    Now, in this patch, instead of the previous workaround, we take a
    similar approach as used in the implicit feedback mode.  The URBs are
    queued at the PCM trigger start like before, but we check whether the
    buffer has been already filled enough before each submission, and
    stop queuing if the data overcomes the threshold.  The remaining URBs
    are kept in the ready list, and they will be retrieved in the URB
    complete callback of other (already queued) URBs.  In the complete
    callback, we try to fill the data and submit as much as possible
    again.  When there is no more available in-flight URBs that may handle
    the pending data, we'll check in PCM ack callback and submit and
    process URBs there in addition.  In this way, the amount of in-flight
    URBs may vary dynamically and flexibly depending on the available data
    without hitting XRUN.
    
    The following things are changed to achieve the behavior above:
    
    * The endpoint prepare callback is changed to return an error code;
      when there is no enough data available, it may return -EAGAIN.
      Currently only prepare_playback_urb() returns the error.
    
      The evaluation of the available data is a bit messy here; we can't
      check with snd_pcm_avail() at the point of prepare callback (as
      runtime->status->hwptr hasn't been updated yet), hence we manually
      estimate the appl_ptr and compare with the internal hwptr_done to
      calculate the available frames.
    
    * snd_usb_endpoint_start() doesn't submit full URBs if the prepare
      callback returns -EAGAIN, and puts the remaining URBs to the ready
      list for the later submission.
    
    * snd_complete_urb() treats the URBs in the low-latency mode similarly
      like the implicit feedback mode, and submissions are done in
      (now exported) snd_usb_queue_pending_output_urbs().
    
    * snd_usb_queue_pending_output_urbs() again checks the error value
      from the prepare callback.  If it's -EAGAIN for the normal stream
      (i.e. not implicit feedback mode), we push it back to the ready list
      again.
    
    * PCM ack callback is introduced for the playback stream, and it calls
      snd_usb_queue_pending_output_urbs() if there is no in-flight URB
      while the stream is running.  This corresponds to the case where the
      system needs the appl_ptr update for re-submitting a new URB.
    
    * snd_usb_queue_pending_output_urbs() and the prepare EP callback
      receive in_stream_lock argument, which is a bool flag indicating the
      call path from PCM ack.  It's needed for avoiding the deadlock of
      snd_pcm_period_elapsed() calls.
    
    * Set the new SNDRV_PCM_INFO_EXPLICIT_SYNC flag when the new
      low-latency mode is deployed.  This assures catching each applptr
      update even in the mmap mode.
    
    Fixes: 4267c5a8 ("ALSA: usb-audio: Work around for XRUN with low latency playback")
    Link: https://lore.kernel.org/r/20210929080844.11583-9-tiwai@suse.deSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
    d5f871f8
endpoint.c 45.6 KB