mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-30 16:07:39 +00:00
d5f871f89e
This is another attempt to improve further the handling of playback stream in the low latency mode. The latest workaround in commit4267c5a8f3
("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:4267c5a8f3
("ALSA: usb-audio: Work around for XRUN with low latency playback") Link: https://lore.kernel.org/r/20210929080844.11583-9-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
207 lines
8.1 KiB
C
207 lines
8.1 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef __USBAUDIO_CARD_H
|
|
#define __USBAUDIO_CARD_H
|
|
|
|
#define MAX_NR_RATES 1024
|
|
#define MAX_PACKS 6 /* per URB */
|
|
#define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */
|
|
#define MAX_URBS 12
|
|
#define SYNC_URBS 4 /* always four urbs for sync */
|
|
#define MAX_QUEUE 18 /* try not to exceed this queue length, in ms */
|
|
|
|
struct audioformat {
|
|
struct list_head list;
|
|
u64 formats; /* ALSA format bits */
|
|
unsigned int channels; /* # channels */
|
|
unsigned int fmt_type; /* USB audio format type (1-3) */
|
|
unsigned int fmt_bits; /* number of significant bits */
|
|
unsigned int frame_size; /* samples per frame for non-audio */
|
|
unsigned char iface; /* interface number */
|
|
unsigned char altsetting; /* corresponding alternate setting */
|
|
unsigned char ep_idx; /* endpoint array index */
|
|
unsigned char altset_idx; /* array index of alternate setting */
|
|
unsigned char attributes; /* corresponding attributes of cs endpoint */
|
|
unsigned char endpoint; /* endpoint */
|
|
unsigned char ep_attr; /* endpoint attributes */
|
|
bool implicit_fb; /* implicit feedback endpoint */
|
|
unsigned char sync_ep; /* sync endpoint number */
|
|
unsigned char sync_iface; /* sync EP interface */
|
|
unsigned char sync_altsetting; /* sync EP alternate setting */
|
|
unsigned char sync_ep_idx; /* sync EP array index */
|
|
unsigned char datainterval; /* log_2 of data packet interval */
|
|
unsigned char protocol; /* UAC_VERSION_1/2/3 */
|
|
unsigned int maxpacksize; /* max. packet size */
|
|
unsigned int rates; /* rate bitmasks */
|
|
unsigned int rate_min, rate_max; /* min/max rates */
|
|
unsigned int nr_rates; /* number of rate table entries */
|
|
unsigned int *rate_table; /* rate table */
|
|
unsigned char clock; /* associated clock */
|
|
struct snd_pcm_chmap_elem *chmap; /* (optional) channel map */
|
|
bool dsd_dop; /* add DOP headers in case of DSD samples */
|
|
bool dsd_bitrev; /* reverse the bits of each DSD sample */
|
|
bool dsd_raw; /* altsetting is raw DSD */
|
|
};
|
|
|
|
struct snd_usb_substream;
|
|
struct snd_usb_iface_ref;
|
|
struct snd_usb_endpoint;
|
|
struct snd_usb_power_domain;
|
|
|
|
struct snd_urb_ctx {
|
|
struct urb *urb;
|
|
unsigned int buffer_size; /* size of data buffer, if data URB */
|
|
struct snd_usb_substream *subs;
|
|
struct snd_usb_endpoint *ep;
|
|
int index; /* index for urb array */
|
|
int packets; /* number of packets per urb */
|
|
int queued; /* queued data bytes by this urb */
|
|
int packet_size[MAX_PACKS_HS]; /* size of packets for next submission */
|
|
struct list_head ready_list;
|
|
};
|
|
|
|
struct snd_usb_endpoint {
|
|
struct snd_usb_audio *chip;
|
|
struct snd_usb_iface_ref *iface_ref;
|
|
|
|
int opened; /* open refcount; protect with chip->mutex */
|
|
atomic_t running; /* running status */
|
|
int ep_num; /* the referenced endpoint number */
|
|
int type; /* SND_USB_ENDPOINT_TYPE_* */
|
|
|
|
unsigned char iface; /* interface number */
|
|
unsigned char altsetting; /* corresponding alternate setting */
|
|
unsigned char ep_idx; /* endpoint array index */
|
|
|
|
atomic_t state; /* running state */
|
|
|
|
int (*prepare_data_urb) (struct snd_usb_substream *subs,
|
|
struct urb *urb,
|
|
bool in_stream_lock);
|
|
void (*retire_data_urb) (struct snd_usb_substream *subs,
|
|
struct urb *urb);
|
|
|
|
struct snd_usb_substream *data_subs;
|
|
struct snd_usb_endpoint *sync_source;
|
|
struct snd_usb_endpoint *sync_sink;
|
|
|
|
struct snd_urb_ctx urb[MAX_URBS];
|
|
|
|
struct snd_usb_packet_info {
|
|
uint32_t packet_size[MAX_PACKS_HS];
|
|
int packets;
|
|
} next_packet[MAX_URBS];
|
|
unsigned int next_packet_head; /* ring buffer offset to read */
|
|
unsigned int next_packet_queued; /* queued items in the ring buffer */
|
|
struct list_head ready_playback_urbs; /* playback URB FIFO for implicit fb */
|
|
|
|
unsigned int nurbs; /* # urbs */
|
|
unsigned long active_mask; /* bitmask of active urbs */
|
|
unsigned long unlink_mask; /* bitmask of unlinked urbs */
|
|
atomic_t submitted_urbs; /* currently submitted urbs */
|
|
char *syncbuf; /* sync buffer for all sync URBs */
|
|
dma_addr_t sync_dma; /* DMA address of syncbuf */
|
|
|
|
unsigned int pipe; /* the data i/o pipe */
|
|
unsigned int packsize[2]; /* small/large packet sizes in samples */
|
|
unsigned int sample_rem; /* remainder from division fs/pps */
|
|
unsigned int sample_accum; /* sample accumulator */
|
|
unsigned int pps; /* packets per second */
|
|
unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */
|
|
unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */
|
|
int freqshift; /* how much to shift the feedback value to get Q16.16 */
|
|
unsigned int freqmax; /* maximum sampling rate, used for buffer management */
|
|
unsigned int phase; /* phase accumulator */
|
|
unsigned int maxpacksize; /* max packet size in bytes */
|
|
unsigned int maxframesize; /* max packet size in frames */
|
|
unsigned int max_urb_frames; /* max URB size in frames */
|
|
unsigned int curpacksize; /* current packet size in bytes (for capture) */
|
|
unsigned int curframesize; /* current packet size in frames (for capture) */
|
|
unsigned int syncmaxsize; /* sync endpoint packet size */
|
|
unsigned int fill_max:1; /* fill max packet size always */
|
|
unsigned int tenor_fb_quirk:1; /* corrupted feedback data */
|
|
unsigned int datainterval; /* log_2 of data packet interval */
|
|
unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */
|
|
unsigned char silence_value;
|
|
unsigned int stride;
|
|
int skip_packets; /* quirks for devices to ignore the first n packets
|
|
in a stream */
|
|
bool implicit_fb_sync; /* syncs with implicit feedback */
|
|
bool lowlatency_playback; /* low-latency playback mode */
|
|
bool need_setup; /* (re-)need for configure? */
|
|
|
|
/* for hw constraints */
|
|
const struct audioformat *cur_audiofmt;
|
|
unsigned int cur_rate;
|
|
snd_pcm_format_t cur_format;
|
|
unsigned int cur_channels;
|
|
unsigned int cur_frame_bytes;
|
|
unsigned int cur_period_frames;
|
|
unsigned int cur_period_bytes;
|
|
unsigned int cur_buffer_periods;
|
|
unsigned char cur_clock;
|
|
|
|
spinlock_t lock;
|
|
struct list_head list;
|
|
};
|
|
|
|
struct media_ctl;
|
|
|
|
struct snd_usb_substream {
|
|
struct snd_usb_stream *stream;
|
|
struct usb_device *dev;
|
|
struct snd_pcm_substream *pcm_substream;
|
|
int direction; /* playback or capture */
|
|
int endpoint; /* assigned endpoint */
|
|
const struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */
|
|
struct snd_usb_power_domain *str_pd; /* UAC3 Power Domain for streaming path */
|
|
unsigned int channels_max; /* max channels in the all audiofmts */
|
|
unsigned int txfr_quirk:1; /* allow sub-frame alignment */
|
|
unsigned int tx_length_quirk:1; /* add length specifier to transfers */
|
|
unsigned int fmt_type; /* USB audio format type (1-3) */
|
|
unsigned int pkt_offset_adj; /* Bytes to drop from beginning of packets (for non-compliant devices) */
|
|
unsigned int stream_offset_adj; /* Bytes to drop from beginning of stream (for non-compliant devices) */
|
|
|
|
unsigned int running: 1; /* running status */
|
|
unsigned int period_elapsed_pending; /* delay period handling */
|
|
|
|
unsigned int buffer_bytes; /* buffer size in bytes */
|
|
unsigned int inflight_bytes; /* in-flight data bytes on buffer (for playback) */
|
|
unsigned int hwptr_done; /* processed byte position in the buffer */
|
|
unsigned int transfer_done; /* processed frames since last period update */
|
|
unsigned int frame_limit; /* limits number of packets in URB */
|
|
|
|
/* data and sync endpoints for this stream */
|
|
unsigned int ep_num; /* the endpoint number */
|
|
struct snd_usb_endpoint *data_endpoint;
|
|
struct snd_usb_endpoint *sync_endpoint;
|
|
unsigned long flags;
|
|
unsigned int speed; /* USB_SPEED_XXX */
|
|
|
|
u64 formats; /* format bitmasks (all or'ed) */
|
|
unsigned int num_formats; /* number of supported audio formats (list) */
|
|
struct list_head fmt_list; /* format list */
|
|
spinlock_t lock;
|
|
|
|
unsigned int last_frame_number; /* stored frame number */
|
|
|
|
struct {
|
|
int marker;
|
|
int channel;
|
|
int byte_idx;
|
|
} dsd_dop;
|
|
|
|
bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */
|
|
bool lowlatency_playback; /* low-latency playback mode */
|
|
struct media_ctl *media_ctl;
|
|
};
|
|
|
|
struct snd_usb_stream {
|
|
struct snd_usb_audio *chip;
|
|
struct snd_pcm *pcm;
|
|
int pcm_index;
|
|
unsigned int fmt_type; /* USB audio format type (1-3) */
|
|
struct snd_usb_substream substream[2];
|
|
struct list_head list;
|
|
};
|
|
|
|
#endif /* __USBAUDIO_CARD_H */
|