2019-05-27 06:55:05 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2010-03-04 18:46:13 +00:00
|
|
|
/*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/init.h>
|
2010-03-29 08:01:48 +00:00
|
|
|
#include <linux/slab.h>
|
2013-04-16 16:01:39 +00:00
|
|
|
#include <linux/bitrev.h>
|
2012-04-12 11:51:12 +00:00
|
|
|
#include <linux/ratelimit.h>
|
2010-03-04 18:46:13 +00:00
|
|
|
#include <linux/usb.h>
|
|
|
|
#include <linux/usb/audio.h>
|
2010-03-11 20:13:20 +00:00
|
|
|
#include <linux/usb/audio-v2.h>
|
2010-03-04 18:46:13 +00:00
|
|
|
|
|
|
|
#include <sound/core.h>
|
|
|
|
#include <sound/pcm.h>
|
|
|
|
#include <sound/pcm_params.h>
|
|
|
|
|
|
|
|
#include "usbaudio.h"
|
|
|
|
#include "card.h"
|
|
|
|
#include "quirks.h"
|
2011-09-14 10:46:57 +00:00
|
|
|
#include "endpoint.h"
|
2010-03-04 18:46:13 +00:00
|
|
|
#include "helper.h"
|
|
|
|
#include "pcm.h"
|
2010-05-31 12:51:31 +00:00
|
|
|
#include "clock.h"
|
2011-03-11 13:51:12 +00:00
|
|
|
#include "power.h"
|
media: sound/usb: Use Media Controller API to share media resources
Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.
Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.
Change the ALSA driver to use the Media Controller API to share media
resources with DVB, and V4L2 drivers on a AU0828 media device.
The Media Controller specific initialization is done after sound card is
registered. ALSA creates Media interface and entity function graph nodes
for Control, Mixer, PCM Playback, and PCM Capture devices.
snd_usb_hw_params() will call Media Controller enable source handler
interface to request the media resource. If resource request is granted,
it will release it from snd_usb_hw_free(). If resource is busy, -EBUSY is
returned.
Media specific cleanup is done in usb_audio_disconnect().
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Shuah Khan <shuah@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2019-04-02 00:40:22 +00:00
|
|
|
#include "media.h"
|
2020-11-23 08:53:43 +00:00
|
|
|
#include "implicit.h"
|
2010-03-04 18:46:13 +00:00
|
|
|
|
2012-04-12 11:51:12 +00:00
|
|
|
#define SUBSTREAM_FLAG_DATA_EP_STARTED 0
|
|
|
|
#define SUBSTREAM_FLAG_SYNC_EP_STARTED 1
|
|
|
|
|
2011-09-07 00:15:34 +00:00
|
|
|
/* return the estimated delay based on USB frame counters */
|
2021-06-01 16:24:53 +00:00
|
|
|
static snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
struct snd_pcm_runtime *runtime)
|
2011-09-07 00:15:34 +00:00
|
|
|
{
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
unsigned int current_frame_number;
|
|
|
|
unsigned int frame_diff;
|
2011-09-07 00:15:34 +00:00
|
|
|
int est_delay;
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
int queued;
|
2011-09-07 00:15:34 +00:00
|
|
|
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
|
|
queued = bytes_to_frames(runtime, subs->inflight_bytes);
|
|
|
|
if (!queued)
|
|
|
|
return 0;
|
|
|
|
} else if (!subs->running) {
|
|
|
|
return 0;
|
|
|
|
}
|
2012-11-23 15:00:37 +00:00
|
|
|
|
2011-09-07 00:15:34 +00:00
|
|
|
current_frame_number = usb_get_current_frame_number(subs->dev);
|
|
|
|
/*
|
|
|
|
* HCD implementations use different widths, use lower 8 bits.
|
|
|
|
* The delay will be managed up to 256ms, which is more than
|
|
|
|
* enough
|
|
|
|
*/
|
|
|
|
frame_diff = (current_frame_number - subs->last_frame_number) & 0xff;
|
|
|
|
|
|
|
|
/* Approximation based on number of samples per USB frame (ms),
|
|
|
|
some truncation for 44.1 but the estimate is good enough */
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
est_delay = frame_diff * runtime->rate / 1000;
|
|
|
|
|
|
|
|
if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
|
|
est_delay = queued - est_delay;
|
|
|
|
if (est_delay < 0)
|
|
|
|
est_delay = 0;
|
|
|
|
}
|
2012-12-19 17:39:05 +00:00
|
|
|
|
2011-09-07 00:15:34 +00:00
|
|
|
return est_delay;
|
|
|
|
}
|
|
|
|
|
2010-03-04 18:46:13 +00:00
|
|
|
/*
|
|
|
|
* return the current pcm pointer. just based on the hwptr_done value.
|
|
|
|
*/
|
|
|
|
static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream)
|
|
|
|
{
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
|
|
struct snd_usb_substream *subs = runtime->private_data;
|
2010-03-04 18:46:13 +00:00
|
|
|
unsigned int hwptr_done;
|
|
|
|
|
ALSA: usb-audio: Avoid nested autoresume calls
After the recent fix of runtime PM for USB-audio driver, we got a
lockdep warning like:
=============================================
[ INFO: possible recursive locking detected ]
4.2.0-rc8+ #61 Not tainted
---------------------------------------------
pulseaudio/980 is trying to acquire lock:
(&chip->shutdown_rwsem){.+.+.+}, at: [<ffffffffa0355dac>] snd_usb_autoresume+0x1d/0x52 [snd_usb_audio]
but task is already holding lock:
(&chip->shutdown_rwsem){.+.+.+}, at: [<ffffffffa0355dac>] snd_usb_autoresume+0x1d/0x52 [snd_usb_audio]
This comes from snd_usb_autoresume() invoking down_read() and it's
used in a nested way. Although it's basically safe, per se (as these
are read locks), it's better to reduce such spurious warnings.
The read lock is needed to guarantee the execution of "shutdown"
(cleanup at disconnection) task after all concurrent tasks are
finished. This can be implemented in another better way.
Also, the current check of chip->in_pm isn't good enough for
protecting the racy execution of multiple auto-resumes.
This patch rewrites the logic of snd_usb_autoresume() & co; namely,
- The recursive call of autopm is avoided by the new refcount,
chip->active. The chip->in_pm flag is removed accordingly.
- Instead of rwsem, another refcount, chip->usage_count, is introduced
for tracking the period to delay the shutdown procedure. At
the last clear of this refcount, wake_up() to the shutdown waiter is
called.
- The shutdown flag is replaced with shutdown atomic count; this is
for reducing the lock.
- Two new helpers are introduced to simplify the management of these
refcounts; snd_usb_lock_shutdown() increases the usage_count, checks
the shutdown state, and does autoresume. snd_usb_unlock_shutdown()
does the opposite. Most of mixer and other codes just need this,
and simply returns an error if it receives an error from lock.
Fixes: 9003ebb13f61 ('ALSA: usb-audio: Fix runtime PM unbalance')
Reported-and-tested-by: Alexnader Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-08-25 14:09:00 +00:00
|
|
|
if (atomic_read(&subs->stream->chip->shutdown))
|
2012-10-12 13:12:55 +00:00
|
|
|
return SNDRV_PCM_POS_XRUN;
|
2010-03-04 18:46:13 +00:00
|
|
|
spin_lock(&subs->lock);
|
|
|
|
hwptr_done = subs->hwptr_done;
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
runtime->delay = snd_usb_pcm_delay(subs, runtime);
|
2010-03-04 18:46:13 +00:00
|
|
|
spin_unlock(&subs->lock);
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
return bytes_to_frames(runtime, hwptr_done);
|
2010-03-04 18:46:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* find a matching audio format
|
|
|
|
*/
|
2020-11-23 08:53:33 +00:00
|
|
|
static const struct audioformat *
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
find_format(struct list_head *fmt_list_head, snd_pcm_format_t format,
|
|
|
|
unsigned int rate, unsigned int channels, bool strict_match,
|
|
|
|
struct snd_usb_substream *subs)
|
2010-03-04 18:46:13 +00:00
|
|
|
{
|
2020-11-23 08:53:33 +00:00
|
|
|
const struct audioformat *fp;
|
|
|
|
const struct audioformat *found = NULL;
|
2010-03-04 18:46:13 +00:00
|
|
|
int cur_attr = 0, attr;
|
|
|
|
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
list_for_each_entry(fp, fmt_list_head, list) {
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
if (strict_match) {
|
|
|
|
if (!(fp->formats & pcm_format_to_bits(format)))
|
|
|
|
continue;
|
|
|
|
if (fp->channels != channels)
|
|
|
|
continue;
|
|
|
|
}
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
if (rate < fp->rate_min || rate > fp->rate_max)
|
2010-03-04 18:46:13 +00:00
|
|
|
continue;
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
if (!(fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) {
|
2010-03-04 18:46:13 +00:00
|
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < fp->nr_rates; i++)
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
if (fp->rate_table[i] == rate)
|
2010-03-04 18:46:13 +00:00
|
|
|
break;
|
|
|
|
if (i >= fp->nr_rates)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
attr = fp->ep_attr & USB_ENDPOINT_SYNCTYPE;
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
if (!found) {
|
2010-03-04 18:46:13 +00:00
|
|
|
found = fp;
|
|
|
|
cur_attr = attr;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* avoid async out and adaptive in if the other method
|
|
|
|
* supports the same format.
|
|
|
|
* this is a workaround for the case like
|
|
|
|
* M-audio audiophile USB.
|
|
|
|
*/
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
if (subs && attr != cur_attr) {
|
2010-03-04 18:46:13 +00:00
|
|
|
if ((attr == USB_ENDPOINT_SYNC_ASYNC &&
|
|
|
|
subs->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
|
|
|
|
(attr == USB_ENDPOINT_SYNC_ADAPTIVE &&
|
|
|
|
subs->direction == SNDRV_PCM_STREAM_CAPTURE))
|
|
|
|
continue;
|
|
|
|
if ((cur_attr == USB_ENDPOINT_SYNC_ASYNC &&
|
|
|
|
subs->direction == SNDRV_PCM_STREAM_PLAYBACK) ||
|
|
|
|
(cur_attr == USB_ENDPOINT_SYNC_ADAPTIVE &&
|
|
|
|
subs->direction == SNDRV_PCM_STREAM_CAPTURE)) {
|
|
|
|
found = fp;
|
|
|
|
cur_attr = attr;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* find the format with the largest max. packet size */
|
|
|
|
if (fp->maxpacksize > found->maxpacksize) {
|
|
|
|
found = fp;
|
|
|
|
cur_attr = attr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
2020-11-23 08:53:33 +00:00
|
|
|
static const struct audioformat *
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
find_substream_format(struct snd_usb_substream *subs,
|
|
|
|
const struct snd_pcm_hw_params *params)
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
{
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
return find_format(&subs->fmt_list, params_format(params),
|
|
|
|
params_rate(params), params_channels(params),
|
|
|
|
true, subs);
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
}
|
|
|
|
|
2022-12-15 15:30:37 +00:00
|
|
|
bool snd_usb_pcm_has_fixed_rate(struct snd_usb_substream *subs)
|
|
|
|
{
|
|
|
|
const struct audioformat *fp;
|
2023-01-13 08:53:11 +00:00
|
|
|
struct snd_usb_audio *chip;
|
2022-12-15 15:30:37 +00:00
|
|
|
int rate = -1;
|
|
|
|
|
2023-01-09 14:11:33 +00:00
|
|
|
if (!subs)
|
|
|
|
return false;
|
2023-01-13 08:53:11 +00:00
|
|
|
chip = subs->stream->chip;
|
2022-12-15 15:30:37 +00:00
|
|
|
if (!(chip->quirk_flags & QUIRK_FLAG_FIXED_RATE))
|
|
|
|
return false;
|
|
|
|
list_for_each_entry(fp, &subs->fmt_list, list) {
|
|
|
|
if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)
|
|
|
|
return false;
|
|
|
|
if (fp->nr_rates < 1)
|
|
|
|
continue;
|
|
|
|
if (fp->nr_rates > 1)
|
|
|
|
return false;
|
|
|
|
if (rate < 0) {
|
|
|
|
rate = fp->rate_table[0];
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (rate != fp->rate_table[0])
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
static int init_pitch_v1(struct snd_usb_audio *chip, int ep)
|
2010-03-04 18:46:17 +00:00
|
|
|
{
|
|
|
|
struct usb_device *dev = chip->dev;
|
|
|
|
unsigned char data[1];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
data[0] = 1;
|
2018-05-27 13:18:22 +00:00
|
|
|
err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
|
|
|
|
USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
|
|
|
|
UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep,
|
|
|
|
data, sizeof(data));
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
return err;
|
2010-03-04 18:46:17 +00:00
|
|
|
}
|
2010-03-04 18:46:13 +00:00
|
|
|
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
static int init_pitch_v2(struct snd_usb_audio *chip, int ep)
|
2010-05-26 16:11:39 +00:00
|
|
|
{
|
|
|
|
struct usb_device *dev = chip->dev;
|
|
|
|
unsigned char data[1];
|
|
|
|
int err;
|
|
|
|
|
|
|
|
data[0] = 1;
|
2018-05-27 13:18:22 +00:00
|
|
|
err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
|
|
|
|
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
|
|
|
|
UAC2_EP_CS_PITCH << 8, 0,
|
|
|
|
data, sizeof(data));
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
return err;
|
2010-05-26 16:11:39 +00:00
|
|
|
}
|
|
|
|
|
2010-03-04 18:46:13 +00:00
|
|
|
/*
|
2010-05-26 16:11:39 +00:00
|
|
|
* initialize the pitch control and sample rate
|
2010-03-04 18:46:13 +00:00
|
|
|
*/
|
2020-11-23 08:53:26 +00:00
|
|
|
int snd_usb_init_pitch(struct snd_usb_audio *chip,
|
2020-11-23 08:53:33 +00:00
|
|
|
const struct audioformat *fmt)
|
2010-03-04 18:46:13 +00:00
|
|
|
{
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
int err;
|
|
|
|
|
2010-05-26 16:11:39 +00:00
|
|
|
/* if endpoint doesn't have pitch control, bail out */
|
|
|
|
if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL))
|
|
|
|
return 0;
|
|
|
|
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
usb_audio_dbg(chip, "enable PITCH for EP 0x%x\n", fmt->endpoint);
|
|
|
|
|
2013-01-31 20:39:17 +00:00
|
|
|
switch (fmt->protocol) {
|
2010-03-04 18:46:17 +00:00
|
|
|
case UAC_VERSION_1:
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
err = init_pitch_v1(chip, fmt->endpoint);
|
|
|
|
break;
|
|
|
|
case UAC_VERSION_2:
|
|
|
|
err = init_pitch_v2(chip, fmt->endpoint);
|
|
|
|
break;
|
2010-09-03 08:53:11 +00:00
|
|
|
default:
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2010-03-04 18:46:17 +00:00
|
|
|
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
if (err < 0) {
|
|
|
|
usb_audio_err(chip, "failed to enable PITCH for EP 0x%x\n",
|
|
|
|
fmt->endpoint);
|
|
|
|
return err;
|
2010-03-04 18:46:17 +00:00
|
|
|
}
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
|
|
|
|
return 0;
|
2010-03-04 18:46:17 +00:00
|
|
|
}
|
|
|
|
|
2021-09-29 08:08:44 +00:00
|
|
|
static bool stop_endpoints(struct snd_usb_substream *subs, bool keep_pending)
|
2020-11-23 08:53:27 +00:00
|
|
|
{
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
bool stopped = 0;
|
|
|
|
|
2020-11-23 08:53:27 +00:00
|
|
|
if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) {
|
2021-09-29 08:08:44 +00:00
|
|
|
snd_usb_endpoint_stop(subs->sync_endpoint, keep_pending);
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
stopped = true;
|
2020-11-23 08:53:27 +00:00
|
|
|
}
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) {
|
2021-09-29 08:08:44 +00:00
|
|
|
snd_usb_endpoint_stop(subs->data_endpoint, keep_pending);
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
stopped = true;
|
|
|
|
}
|
|
|
|
return stopped;
|
2020-11-23 08:53:27 +00:00
|
|
|
}
|
|
|
|
|
2017-01-04 22:37:46 +00:00
|
|
|
static int start_endpoints(struct snd_usb_substream *subs)
|
2012-04-12 11:51:12 +00:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!subs->data_endpoint)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) {
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
err = snd_usb_endpoint_start(subs->data_endpoint);
|
2012-04-12 11:51:12 +00:00
|
|
|
if (err < 0) {
|
|
|
|
clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags);
|
2020-11-23 08:53:27 +00:00
|
|
|
goto error;
|
2012-04-12 11:51:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (subs->sync_endpoint &&
|
|
|
|
!test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) {
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
err = snd_usb_endpoint_start(subs->sync_endpoint);
|
2012-04-12 11:51:12 +00:00
|
|
|
if (err < 0) {
|
|
|
|
clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags);
|
2020-11-23 08:53:27 +00:00
|
|
|
goto error;
|
2012-04-12 11:51:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2020-11-23 08:53:27 +00:00
|
|
|
|
|
|
|
error:
|
2021-09-29 08:08:44 +00:00
|
|
|
stop_endpoints(subs, false);
|
2020-11-23 08:53:27 +00:00
|
|
|
return err;
|
2012-04-12 11:51:12 +00:00
|
|
|
}
|
|
|
|
|
2019-12-10 06:34:54 +00:00
|
|
|
static void sync_pending_stops(struct snd_usb_substream *subs)
|
|
|
|
{
|
|
|
|
snd_usb_endpoint_sync_pending_stop(subs->sync_endpoint);
|
|
|
|
snd_usb_endpoint_sync_pending_stop(subs->data_endpoint);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* PCM sync_stop callback */
|
|
|
|
static int snd_usb_pcm_sync_stop(struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct snd_usb_substream *subs = substream->runtime->private_data;
|
|
|
|
|
2021-02-06 20:30:52 +00:00
|
|
|
sync_pending_stops(subs);
|
2019-12-10 06:34:54 +00:00
|
|
|
return 0;
|
2012-04-12 11:51:12 +00:00
|
|
|
}
|
|
|
|
|
2020-11-23 08:53:43 +00:00
|
|
|
/* Set up sync endpoint */
|
2020-11-23 08:53:14 +00:00
|
|
|
int snd_usb_audioformat_set_sync_ep(struct snd_usb_audio *chip,
|
|
|
|
struct audioformat *fmt)
|
2013-08-03 08:50:18 +00:00
|
|
|
{
|
2020-11-23 08:53:14 +00:00
|
|
|
struct usb_device *dev = chip->dev;
|
|
|
|
struct usb_host_interface *alts;
|
|
|
|
struct usb_interface_descriptor *altsd;
|
|
|
|
unsigned int ep, attr, sync_attr;
|
|
|
|
bool is_playback;
|
2013-08-03 08:50:18 +00:00
|
|
|
int err;
|
|
|
|
|
2022-06-06 16:09:10 +00:00
|
|
|
if (fmt->sync_ep)
|
|
|
|
return 0; /* already set up */
|
|
|
|
|
2020-11-23 08:53:22 +00:00
|
|
|
alts = snd_usb_get_host_interface(chip, fmt->iface, fmt->altsetting);
|
2020-11-23 08:53:14 +00:00
|
|
|
if (!alts)
|
2019-01-31 14:32:35 +00:00
|
|
|
return 0;
|
2020-11-23 08:53:14 +00:00
|
|
|
altsd = get_iface_desc(alts);
|
|
|
|
|
2020-11-23 08:53:43 +00:00
|
|
|
err = snd_usb_parse_implicit_fb_quirk(chip, fmt, alts);
|
|
|
|
if (err > 0)
|
|
|
|
return 0; /* matched */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Generic sync EP handling
|
|
|
|
*/
|
2019-01-31 14:32:35 +00:00
|
|
|
|
2022-06-06 16:09:09 +00:00
|
|
|
if (fmt->ep_idx > 0 || altsd->bNumEndpoints < 2)
|
2013-08-03 08:50:19 +00:00
|
|
|
return 0;
|
2012-04-12 11:51:14 +00:00
|
|
|
|
2020-11-23 08:53:43 +00:00
|
|
|
is_playback = !(get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN);
|
2020-11-23 08:53:14 +00:00
|
|
|
attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE;
|
2015-08-14 22:19:43 +00:00
|
|
|
if ((is_playback && (attr == USB_ENDPOINT_SYNC_SYNC ||
|
|
|
|
attr == USB_ENDPOINT_SYNC_ADAPTIVE)) ||
|
2013-08-03 08:50:19 +00:00
|
|
|
(!is_playback && attr != USB_ENDPOINT_SYNC_ADAPTIVE))
|
|
|
|
return 0;
|
2012-04-12 11:51:12 +00:00
|
|
|
|
2020-11-23 08:53:14 +00:00
|
|
|
sync_attr = get_endpoint(alts, 1)->bmAttributes;
|
|
|
|
|
2015-08-14 22:19:43 +00:00
|
|
|
/*
|
|
|
|
* In case of illegal SYNC_NONE for OUT endpoint, we keep going to see
|
|
|
|
* if we don't find a sync endpoint, as on M-Audio Transit. In case of
|
|
|
|
* error fall back to SYNC mode and don't create sync endpoint
|
|
|
|
*/
|
|
|
|
|
2013-08-03 08:50:19 +00:00
|
|
|
/* check sync-pipe endpoint */
|
|
|
|
/* ... and check descriptor size before accessing bSynchAddress
|
|
|
|
because there is a version of the SB Audigy 2 NX firmware lacking
|
|
|
|
the audio fields in the endpoint descriptors */
|
2020-11-23 08:53:14 +00:00
|
|
|
if ((sync_attr & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC ||
|
2013-08-03 08:50:19 +00:00
|
|
|
(get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
|
2013-08-03 08:50:20 +00:00
|
|
|
get_endpoint(alts, 1)->bSynchAddress != 0)) {
|
2014-02-26 12:02:17 +00:00
|
|
|
dev_err(&dev->dev,
|
|
|
|
"%d:%d : invalid sync pipe. bmAttributes %02x, bLength %d, bSynchAddress %02x\n",
|
|
|
|
fmt->iface, fmt->altsetting,
|
2013-08-03 08:50:19 +00:00
|
|
|
get_endpoint(alts, 1)->bmAttributes,
|
|
|
|
get_endpoint(alts, 1)->bLength,
|
|
|
|
get_endpoint(alts, 1)->bSynchAddress);
|
2015-08-14 22:19:43 +00:00
|
|
|
if (is_playback && attr == USB_ENDPOINT_SYNC_NONE)
|
|
|
|
return 0;
|
2013-08-03 08:50:19 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
ep = get_endpoint(alts, 1)->bEndpointAddress;
|
2013-08-03 08:50:20 +00:00
|
|
|
if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
|
2019-08-02 11:52:14 +00:00
|
|
|
get_endpoint(alts, 0)->bSynchAddress != 0 &&
|
2013-08-03 08:50:19 +00:00
|
|
|
((is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
|
|
|
|
(!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) {
|
2014-02-26 12:02:17 +00:00
|
|
|
dev_err(&dev->dev,
|
|
|
|
"%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n",
|
|
|
|
fmt->iface, fmt->altsetting,
|
2013-08-03 08:50:19 +00:00
|
|
|
is_playback, ep, get_endpoint(alts, 0)->bSynchAddress);
|
2015-08-14 22:19:43 +00:00
|
|
|
if (is_playback && attr == USB_ENDPOINT_SYNC_NONE)
|
|
|
|
return 0;
|
2013-08-03 08:50:19 +00:00
|
|
|
return -EINVAL;
|
2012-04-12 11:51:12 +00:00
|
|
|
}
|
2010-03-04 18:46:13 +00:00
|
|
|
|
2020-11-23 08:53:14 +00:00
|
|
|
fmt->sync_ep = ep;
|
|
|
|
fmt->sync_iface = altsd->bInterfaceNumber;
|
|
|
|
fmt->sync_altsetting = altsd->bAlternateSetting;
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
fmt->sync_ep_idx = 1;
|
2020-11-23 08:53:14 +00:00
|
|
|
if ((sync_attr & USB_ENDPOINT_USAGE_MASK) == USB_ENDPOINT_USAGE_IMPLICIT_FB)
|
|
|
|
fmt->implicit_fb = 1;
|
|
|
|
|
|
|
|
dev_dbg(&dev->dev, "%d:%d: found sync_ep=0x%x, iface=%d, alt=%d, implicit_fb=%d\n",
|
|
|
|
fmt->iface, fmt->altsetting, fmt->sync_ep, fmt->sync_iface,
|
|
|
|
fmt->sync_altsetting, fmt->implicit_fb);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-07-31 12:28:44 +00:00
|
|
|
static int snd_usb_pcm_change_state(struct snd_usb_substream *subs, int state)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!subs->str_pd)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = snd_usb_power_domain_set(subs->stream->chip, subs->str_pd, state);
|
|
|
|
if (ret < 0) {
|
|
|
|
dev_err(&subs->dev->dev,
|
|
|
|
"Cannot change Power Domain ID: %d to state: %d. Err: %d\n",
|
|
|
|
subs->str_pd->pd_id, state, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int snd_usb_pcm_suspend(struct snd_usb_stream *as)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = snd_usb_pcm_change_state(&as->substream[0], UAC3_PD_STATE_D2);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = snd_usb_pcm_change_state(&as->substream[1], UAC3_PD_STATE_D2);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int snd_usb_pcm_resume(struct snd_usb_stream *as)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2018-07-31 12:28:45 +00:00
|
|
|
ret = snd_usb_pcm_change_state(&as->substream[0], UAC3_PD_STATE_D1);
|
2018-07-31 12:28:44 +00:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2018-07-31 12:28:45 +00:00
|
|
|
ret = snd_usb_pcm_change_state(&as->substream[1], UAC3_PD_STATE_D1);
|
2018-07-31 12:28:44 +00:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
static void close_endpoints(struct snd_usb_audio *chip,
|
|
|
|
struct snd_usb_substream *subs)
|
|
|
|
{
|
|
|
|
if (subs->data_endpoint) {
|
|
|
|
snd_usb_endpoint_set_sync(chip, subs->data_endpoint, NULL);
|
|
|
|
snd_usb_endpoint_close(chip, subs->data_endpoint);
|
|
|
|
subs->data_endpoint = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (subs->sync_endpoint) {
|
|
|
|
snd_usb_endpoint_close(chip, subs->sync_endpoint);
|
|
|
|
subs->sync_endpoint = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-04 18:46:13 +00:00
|
|
|
/*
|
|
|
|
* hw_params callback
|
|
|
|
*
|
|
|
|
* allocate a buffer and set the given audio format.
|
|
|
|
*
|
|
|
|
* so far we use a physically linear buffer although packetize transfer
|
|
|
|
* doesn't need a continuous area.
|
|
|
|
* if sg buffer is supported on the later version of alsa, we'll follow
|
|
|
|
* that.
|
|
|
|
*/
|
|
|
|
static int snd_usb_hw_params(struct snd_pcm_substream *substream,
|
|
|
|
struct snd_pcm_hw_params *hw_params)
|
|
|
|
{
|
|
|
|
struct snd_usb_substream *subs = substream->runtime->private_data;
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
struct snd_usb_audio *chip = subs->stream->chip;
|
2020-11-23 08:53:33 +00:00
|
|
|
const struct audioformat *fmt;
|
|
|
|
const struct audioformat *sync_fmt;
|
2022-12-15 15:30:37 +00:00
|
|
|
bool fixed_rate, sync_fixed_rate;
|
2012-09-18 16:49:48 +00:00
|
|
|
int ret;
|
2010-03-04 18:46:13 +00:00
|
|
|
|
media: sound/usb: Use Media Controller API to share media resources
Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.
Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.
Change the ALSA driver to use the Media Controller API to share media
resources with DVB, and V4L2 drivers on a AU0828 media device.
The Media Controller specific initialization is done after sound card is
registered. ALSA creates Media interface and entity function graph nodes
for Control, Mixer, PCM Playback, and PCM Capture devices.
snd_usb_hw_params() will call Media Controller enable source handler
interface to request the media resource. If resource request is granted,
it will release it from snd_usb_hw_free(). If resource is busy, -EBUSY is
returned.
Media specific cleanup is done in usb_audio_disconnect().
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Shuah Khan <shuah@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2019-04-02 00:40:22 +00:00
|
|
|
ret = snd_media_start_pipeline(subs);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2022-12-15 15:30:37 +00:00
|
|
|
fixed_rate = snd_usb_pcm_has_fixed_rate(subs);
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
fmt = find_substream_format(subs, hw_params);
|
2010-03-04 18:46:13 +00:00
|
|
|
if (!fmt) {
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
usb_audio_dbg(chip,
|
|
|
|
"cannot find format: format=%s, rate=%d, channels=%d\n",
|
|
|
|
snd_pcm_format_name(params_format(hw_params)),
|
|
|
|
params_rate(hw_params), params_channels(hw_params));
|
media: sound/usb: Use Media Controller API to share media resources
Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.
Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.
Change the ALSA driver to use the Media Controller API to share media
resources with DVB, and V4L2 drivers on a AU0828 media device.
The Media Controller specific initialization is done after sound card is
registered. ALSA creates Media interface and entity function graph nodes
for Control, Mixer, PCM Playback, and PCM Capture devices.
snd_usb_hw_params() will call Media Controller enable source handler
interface to request the media resource. If resource request is granted,
it will release it from snd_usb_hw_free(). If resource is busy, -EBUSY is
returned.
Media specific cleanup is done in usb_audio_disconnect().
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Shuah Khan <shuah@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2019-04-02 00:40:22 +00:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto stop_pipeline;
|
2010-03-04 18:46:13 +00:00
|
|
|
}
|
|
|
|
|
2020-11-23 08:53:43 +00:00
|
|
|
if (fmt->implicit_fb) {
|
|
|
|
sync_fmt = snd_usb_find_implicit_fb_sync_format(chip, fmt,
|
|
|
|
hw_params,
|
2022-12-15 15:30:37 +00:00
|
|
|
!substream->stream,
|
|
|
|
&sync_fixed_rate);
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
if (!sync_fmt) {
|
|
|
|
usb_audio_dbg(chip,
|
|
|
|
"cannot find sync format: ep=0x%x, iface=%d:%d, format=%s, rate=%d, channels=%d\n",
|
|
|
|
fmt->sync_ep, fmt->sync_iface,
|
|
|
|
fmt->sync_altsetting,
|
|
|
|
snd_pcm_format_name(params_format(hw_params)),
|
|
|
|
params_rate(hw_params), params_channels(hw_params));
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto stop_pipeline;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sync_fmt = fmt;
|
2022-12-15 15:30:37 +00:00
|
|
|
sync_fixed_rate = fixed_rate;
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = snd_usb_lock_shutdown(chip);
|
ALSA: usb-audio: Avoid nested autoresume calls
After the recent fix of runtime PM for USB-audio driver, we got a
lockdep warning like:
=============================================
[ INFO: possible recursive locking detected ]
4.2.0-rc8+ #61 Not tainted
---------------------------------------------
pulseaudio/980 is trying to acquire lock:
(&chip->shutdown_rwsem){.+.+.+}, at: [<ffffffffa0355dac>] snd_usb_autoresume+0x1d/0x52 [snd_usb_audio]
but task is already holding lock:
(&chip->shutdown_rwsem){.+.+.+}, at: [<ffffffffa0355dac>] snd_usb_autoresume+0x1d/0x52 [snd_usb_audio]
This comes from snd_usb_autoresume() invoking down_read() and it's
used in a nested way. Although it's basically safe, per se (as these
are read locks), it's better to reduce such spurious warnings.
The read lock is needed to guarantee the execution of "shutdown"
(cleanup at disconnection) task after all concurrent tasks are
finished. This can be implemented in another better way.
Also, the current check of chip->in_pm isn't good enough for
protecting the racy execution of multiple auto-resumes.
This patch rewrites the logic of snd_usb_autoresume() & co; namely,
- The recursive call of autopm is avoided by the new refcount,
chip->active. The chip->in_pm flag is removed accordingly.
- Instead of rwsem, another refcount, chip->usage_count, is introduced
for tracking the period to delay the shutdown procedure. At
the last clear of this refcount, wake_up() to the shutdown waiter is
called.
- The shutdown flag is replaced with shutdown atomic count; this is
for reducing the lock.
- Two new helpers are introduced to simplify the management of these
refcounts; snd_usb_lock_shutdown() increases the usage_count, checks
the shutdown state, and does autoresume. snd_usb_unlock_shutdown()
does the opposite. Most of mixer and other codes just need this,
and simply returns an error if it receives an error from lock.
Fixes: 9003ebb13f61 ('ALSA: usb-audio: Fix runtime PM unbalance')
Reported-and-tested-by: Alexnader Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-08-25 14:09:00 +00:00
|
|
|
if (ret < 0)
|
media: sound/usb: Use Media Controller API to share media resources
Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.
Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.
Change the ALSA driver to use the Media Controller API to share media
resources with DVB, and V4L2 drivers on a AU0828 media device.
The Media Controller specific initialization is done after sound card is
registered. ALSA creates Media interface and entity function graph nodes
for Control, Mixer, PCM Playback, and PCM Capture devices.
snd_usb_hw_params() will call Media Controller enable source handler
interface to request the media resource. If resource request is granted,
it will release it from snd_usb_hw_free(). If resource is busy, -EBUSY is
returned.
Media specific cleanup is done in usb_audio_disconnect().
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Shuah Khan <shuah@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2019-04-02 00:40:22 +00:00
|
|
|
goto stop_pipeline;
|
2018-07-31 12:28:45 +00:00
|
|
|
|
|
|
|
ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0);
|
|
|
|
if (ret < 0)
|
|
|
|
goto unlock;
|
|
|
|
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
if (subs->data_endpoint) {
|
|
|
|
if (snd_usb_endpoint_compatible(chip, subs->data_endpoint,
|
|
|
|
fmt, hw_params))
|
|
|
|
goto unlock;
|
2023-01-02 17:07:57 +00:00
|
|
|
if (stop_endpoints(subs, false))
|
|
|
|
sync_pending_stops(subs);
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
close_endpoints(chip, subs);
|
|
|
|
}
|
|
|
|
|
2022-12-15 15:30:37 +00:00
|
|
|
subs->data_endpoint = snd_usb_endpoint_open(chip, fmt, hw_params, false, fixed_rate);
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
if (!subs->data_endpoint) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fmt->sync_ep) {
|
|
|
|
subs->sync_endpoint = snd_usb_endpoint_open(chip, sync_fmt,
|
|
|
|
hw_params,
|
2022-12-15 15:30:37 +00:00
|
|
|
fmt == sync_fmt,
|
|
|
|
sync_fixed_rate);
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
if (!subs->sync_endpoint) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
snd_usb_endpoint_set_sync(chip, subs->data_endpoint,
|
|
|
|
subs->sync_endpoint);
|
|
|
|
}
|
|
|
|
|
2020-11-23 08:53:36 +00:00
|
|
|
mutex_lock(&chip->mutex);
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
subs->cur_audiofmt = fmt;
|
2020-11-23 08:53:36 +00:00
|
|
|
mutex_unlock(&chip->mutex);
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
|
ALSA: usb-audio: Split endpoint setups for hw_params and prepare (take#2)
This is a second attempt to fix the bug appearing on Android with the
recent kernel; the first try was ff878b408a03 and reverted at commit
79764ec772bc.
The details taken from the v1 patch:
One of the former changes for the endpoint management was the more
consistent setup of endpoints at hw_params.
snd_usb_endpoint_configure() is a single function that does the full
setup, and it's called from both PCM hw_params and prepare callbacks.
Although the EP setup at the prepare phase is usually skipped (by
checking need_setup flag), it may be still effective in some cases
like suspend/resume that requires the interface setup again.
As it's a full and single setup, the invocation of
snd_usb_endpoint_configure() includes not only the USB interface setup
but also the buffer release and allocation. OTOH, doing the buffer
release and re-allocation at PCM prepare phase is rather superfluous,
and better to be done only in the hw_params phase.
For those optimizations, this patch splits the endpoint setup to two
phases: snd_usb_endpoint_set_params() and snd_usb_endpoint_prepare(),
to be called from hw_params and from prepare, respectively.
Note that this patch changes the driver operation slightly,
effectively moving the USB interface setup again to PCM prepare stage
instead of hw_params stage, while the buffer allocation and such
initializations are still done at hw_params stage.
And, the change of the USB interface setup timing (moving to prepare)
gave an interesting "fix", too: it was reported that the recent
kernels caused silent output at the beginning on playbacks on some
devices on Android, and this change casually fixed the regression.
It seems that those devices are picky about the sample rate change (or
the interface change?), and don't follow the too immediate rate
changes.
Meanwhile, Android operates the PCM in the following order:
- open, then hw_params with the possibly highest sample rate
- close without prepare
- re-open, hw_params with the normal sample rate
- prepare, and start streaming
This procedure ended up the hw_params twice with different rates, and
because the recent kernel did set up the sample rate twice one and
after, it screwed up the device. OTOH, the earlier kernels didn't set
up the USB interface at hw_params, hence this problem didn't appear.
Now, with this patch, the USB interface setup is again back to the
prepare phase, and it works around the problem automagically.
Although we should address the sample rate problem in a more solid
way in future, let's keep things working as before for now.
***
What's new in the take#2 patch:
- The regression caused by the v1 patch (bko#216500) was due to the
missing check of need_setup flag at hw_params. Now the check is
added, and the snd_usb_endpoint_set_params() call is skipped when
the running EP is re-opened.
- There was another bug in v1 where the clock reference rate wasn't
updated at hw_params phase, which may lead to a lack of the proper
hw constraints when an application doesn't issue the prepare but
only the hw_params call. This patch fixes it as well by tracking
the clock rate change in the prepare callback with a new flag
"need_update" for the clock reference object, just like others.
- The configure_endpoints() are simplified and folded back into
snd_usb_pcm_prepare().
Fixes: bf6313a0ff76 ("ALSA: usb-audio: Refactor endpoint management")
Fixes: ff878b408a03 ("ALSA: usb-audio: Split endpoint setups for hw_params and prepare")
Reported-by: chihhao chen <chihhao.chen@mediatek.com>
Link: https://lore.kernel.org/r/87e6d6ae69d68dc588ac9acc8c0f24d6188375c3.camel@mediatek.com
Link: https://lore.kernel.org/r/20220901124136.4984-1-tiwai@suse.de
Link: https://bugzilla.kernel.org/show_bug.cgi?id=216500
Link: https://lore.kernel.org/r/20220920181106.4894-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2022-09-20 18:11:06 +00:00
|
|
|
if (!subs->data_endpoint->need_setup)
|
|
|
|
goto unlock;
|
|
|
|
|
|
|
|
if (subs->sync_endpoint) {
|
|
|
|
ret = snd_usb_endpoint_set_params(chip, subs->sync_endpoint);
|
|
|
|
if (ret < 0)
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = snd_usb_endpoint_set_params(chip, subs->data_endpoint);
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
|
2018-07-31 12:28:45 +00:00
|
|
|
unlock:
|
media: sound/usb: Use Media Controller API to share media resources
Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.
Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.
Change the ALSA driver to use the Media Controller API to share media
resources with DVB, and V4L2 drivers on a AU0828 media device.
The Media Controller specific initialization is done after sound card is
registered. ALSA creates Media interface and entity function graph nodes
for Control, Mixer, PCM Playback, and PCM Capture devices.
snd_usb_hw_params() will call Media Controller enable source handler
interface to request the media resource. If resource request is granted,
it will release it from snd_usb_hw_free(). If resource is busy, -EBUSY is
returned.
Media specific cleanup is done in usb_audio_disconnect().
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Shuah Khan <shuah@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2019-04-02 00:40:22 +00:00
|
|
|
if (ret < 0)
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
close_endpoints(chip, subs);
|
media: sound/usb: Use Media Controller API to share media resources
Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.
Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.
Change the ALSA driver to use the Media Controller API to share media
resources with DVB, and V4L2 drivers on a AU0828 media device.
The Media Controller specific initialization is done after sound card is
registered. ALSA creates Media interface and entity function graph nodes
for Control, Mixer, PCM Playback, and PCM Capture devices.
snd_usb_hw_params() will call Media Controller enable source handler
interface to request the media resource. If resource request is granted,
it will release it from snd_usb_hw_free(). If resource is busy, -EBUSY is
returned.
Media specific cleanup is done in usb_audio_disconnect().
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Shuah Khan <shuah@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2019-04-02 00:40:22 +00:00
|
|
|
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
snd_usb_unlock_shutdown(chip);
|
media: sound/usb: Use Media Controller API to share media resources
Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.
Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.
Change the ALSA driver to use the Media Controller API to share media
resources with DVB, and V4L2 drivers on a AU0828 media device.
The Media Controller specific initialization is done after sound card is
registered. ALSA creates Media interface and entity function graph nodes
for Control, Mixer, PCM Playback, and PCM Capture devices.
snd_usb_hw_params() will call Media Controller enable source handler
interface to request the media resource. If resource request is granted,
it will release it from snd_usb_hw_free(). If resource is busy, -EBUSY is
returned.
Media specific cleanup is done in usb_audio_disconnect().
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Shuah Khan <shuah@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2019-04-02 00:40:22 +00:00
|
|
|
stop_pipeline:
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
if (ret < 0)
|
|
|
|
snd_media_stop_pipeline(subs);
|
|
|
|
|
2018-07-31 12:28:45 +00:00
|
|
|
return ret;
|
2010-03-04 18:46:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* hw_free callback
|
|
|
|
*
|
|
|
|
* reset the audio format and release the buffer
|
|
|
|
*/
|
|
|
|
static int snd_usb_hw_free(struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct snd_usb_substream *subs = substream->runtime->private_data;
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
struct snd_usb_audio *chip = subs->stream->chip;
|
2010-03-04 18:46:13 +00:00
|
|
|
|
media: sound/usb: Use Media Controller API to share media resources
Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.
Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.
Change the ALSA driver to use the Media Controller API to share media
resources with DVB, and V4L2 drivers on a AU0828 media device.
The Media Controller specific initialization is done after sound card is
registered. ALSA creates Media interface and entity function graph nodes
for Control, Mixer, PCM Playback, and PCM Capture devices.
snd_usb_hw_params() will call Media Controller enable source handler
interface to request the media resource. If resource request is granted,
it will release it from snd_usb_hw_free(). If resource is busy, -EBUSY is
returned.
Media specific cleanup is done in usb_audio_disconnect().
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Shuah Khan <shuah@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2019-04-02 00:40:22 +00:00
|
|
|
snd_media_stop_pipeline(subs);
|
2020-11-23 08:53:36 +00:00
|
|
|
mutex_lock(&chip->mutex);
|
2010-03-04 18:46:13 +00:00
|
|
|
subs->cur_audiofmt = NULL;
|
2020-11-23 08:53:36 +00:00
|
|
|
mutex_unlock(&chip->mutex);
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
if (!snd_usb_lock_shutdown(chip)) {
|
2021-09-29 08:08:44 +00:00
|
|
|
if (stop_endpoints(subs, false))
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
sync_pending_stops(subs);
|
|
|
|
close_endpoints(chip, subs);
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
snd_usb_unlock_shutdown(chip);
|
2012-10-12 13:12:55 +00:00
|
|
|
}
|
2018-05-27 11:01:17 +00:00
|
|
|
|
2019-12-09 09:49:42 +00:00
|
|
|
return 0;
|
2010-03-04 18:46:13 +00:00
|
|
|
}
|
|
|
|
|
2021-11-19 10:24:59 +00:00
|
|
|
/* free-wheeling mode? (e.g. dmix) */
|
|
|
|
static int in_free_wheeling_mode(struct snd_pcm_runtime *runtime)
|
|
|
|
{
|
|
|
|
return runtime->stop_threshold > runtime->buffer_size;
|
|
|
|
}
|
|
|
|
|
2021-09-29 08:08:38 +00:00
|
|
|
/* check whether early start is needed for playback stream */
|
2021-09-29 08:08:39 +00:00
|
|
|
static int lowlatency_playback_available(struct snd_pcm_runtime *runtime,
|
|
|
|
struct snd_usb_substream *subs)
|
2021-09-29 08:08:38 +00:00
|
|
|
{
|
|
|
|
struct snd_usb_audio *chip = subs->stream->chip;
|
|
|
|
|
|
|
|
if (subs->direction == SNDRV_PCM_STREAM_CAPTURE)
|
|
|
|
return false;
|
|
|
|
/* disabled via module option? */
|
|
|
|
if (!chip->lowlatency)
|
|
|
|
return false;
|
2021-11-19 10:24:59 +00:00
|
|
|
if (in_free_wheeling_mode(runtime))
|
2021-09-29 08:08:39 +00:00
|
|
|
return false;
|
2021-09-29 08:08:40 +00:00
|
|
|
/* implicit feedback mode has own operation mode */
|
|
|
|
if (snd_usb_endpoint_implicit_feedback_sink(subs->data_endpoint))
|
|
|
|
return false;
|
2021-09-29 08:08:38 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-03-04 18:46:13 +00:00
|
|
|
/*
|
|
|
|
* prepare callback
|
|
|
|
*
|
|
|
|
* only a few subtle things...
|
|
|
|
*/
|
|
|
|
static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
|
|
struct snd_usb_substream *subs = runtime->private_data;
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
struct snd_usb_audio *chip = subs->stream->chip;
|
2022-12-05 13:21:24 +00:00
|
|
|
int retry = 0;
|
2012-09-18 16:49:48 +00:00
|
|
|
int ret;
|
2010-03-04 18:46:13 +00:00
|
|
|
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
ret = snd_usb_lock_shutdown(chip);
|
ALSA: usb-audio: Avoid nested autoresume calls
After the recent fix of runtime PM for USB-audio driver, we got a
lockdep warning like:
=============================================
[ INFO: possible recursive locking detected ]
4.2.0-rc8+ #61 Not tainted
---------------------------------------------
pulseaudio/980 is trying to acquire lock:
(&chip->shutdown_rwsem){.+.+.+}, at: [<ffffffffa0355dac>] snd_usb_autoresume+0x1d/0x52 [snd_usb_audio]
but task is already holding lock:
(&chip->shutdown_rwsem){.+.+.+}, at: [<ffffffffa0355dac>] snd_usb_autoresume+0x1d/0x52 [snd_usb_audio]
This comes from snd_usb_autoresume() invoking down_read() and it's
used in a nested way. Although it's basically safe, per se (as these
are read locks), it's better to reduce such spurious warnings.
The read lock is needed to guarantee the execution of "shutdown"
(cleanup at disconnection) task after all concurrent tasks are
finished. This can be implemented in another better way.
Also, the current check of chip->in_pm isn't good enough for
protecting the racy execution of multiple auto-resumes.
This patch rewrites the logic of snd_usb_autoresume() & co; namely,
- The recursive call of autopm is avoided by the new refcount,
chip->active. The chip->in_pm flag is removed accordingly.
- Instead of rwsem, another refcount, chip->usage_count, is introduced
for tracking the period to delay the shutdown procedure. At
the last clear of this refcount, wake_up() to the shutdown waiter is
called.
- The shutdown flag is replaced with shutdown atomic count; this is
for reducing the lock.
- Two new helpers are introduced to simplify the management of these
refcounts; snd_usb_lock_shutdown() increases the usage_count, checks
the shutdown state, and does autoresume. snd_usb_unlock_shutdown()
does the opposite. Most of mixer and other codes just need this,
and simply returns an error if it receives an error from lock.
Fixes: 9003ebb13f61 ('ALSA: usb-audio: Fix runtime PM unbalance')
Reported-and-tested-by: Alexnader Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-08-25 14:09:00 +00:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2012-10-12 13:12:55 +00:00
|
|
|
if (snd_BUG_ON(!subs->data_endpoint)) {
|
|
|
|
ret = -EIO;
|
|
|
|
goto unlock;
|
|
|
|
}
|
2012-04-12 11:51:12 +00:00
|
|
|
|
2023-06-12 13:28:18 +00:00
|
|
|
ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0);
|
|
|
|
if (ret < 0)
|
|
|
|
goto unlock;
|
|
|
|
|
2022-12-05 13:21:24 +00:00
|
|
|
again:
|
ALSA: usb-audio: Split endpoint setups for hw_params and prepare (take#2)
This is a second attempt to fix the bug appearing on Android with the
recent kernel; the first try was ff878b408a03 and reverted at commit
79764ec772bc.
The details taken from the v1 patch:
One of the former changes for the endpoint management was the more
consistent setup of endpoints at hw_params.
snd_usb_endpoint_configure() is a single function that does the full
setup, and it's called from both PCM hw_params and prepare callbacks.
Although the EP setup at the prepare phase is usually skipped (by
checking need_setup flag), it may be still effective in some cases
like suspend/resume that requires the interface setup again.
As it's a full and single setup, the invocation of
snd_usb_endpoint_configure() includes not only the USB interface setup
but also the buffer release and allocation. OTOH, doing the buffer
release and re-allocation at PCM prepare phase is rather superfluous,
and better to be done only in the hw_params phase.
For those optimizations, this patch splits the endpoint setup to two
phases: snd_usb_endpoint_set_params() and snd_usb_endpoint_prepare(),
to be called from hw_params and from prepare, respectively.
Note that this patch changes the driver operation slightly,
effectively moving the USB interface setup again to PCM prepare stage
instead of hw_params stage, while the buffer allocation and such
initializations are still done at hw_params stage.
And, the change of the USB interface setup timing (moving to prepare)
gave an interesting "fix", too: it was reported that the recent
kernels caused silent output at the beginning on playbacks on some
devices on Android, and this change casually fixed the regression.
It seems that those devices are picky about the sample rate change (or
the interface change?), and don't follow the too immediate rate
changes.
Meanwhile, Android operates the PCM in the following order:
- open, then hw_params with the possibly highest sample rate
- close without prepare
- re-open, hw_params with the normal sample rate
- prepare, and start streaming
This procedure ended up the hw_params twice with different rates, and
because the recent kernel did set up the sample rate twice one and
after, it screwed up the device. OTOH, the earlier kernels didn't set
up the USB interface at hw_params, hence this problem didn't appear.
Now, with this patch, the USB interface setup is again back to the
prepare phase, and it works around the problem automagically.
Although we should address the sample rate problem in a more solid
way in future, let's keep things working as before for now.
***
What's new in the take#2 patch:
- The regression caused by the v1 patch (bko#216500) was due to the
missing check of need_setup flag at hw_params. Now the check is
added, and the snd_usb_endpoint_set_params() call is skipped when
the running EP is re-opened.
- There was another bug in v1 where the clock reference rate wasn't
updated at hw_params phase, which may lead to a lack of the proper
hw constraints when an application doesn't issue the prepare but
only the hw_params call. This patch fixes it as well by tracking
the clock rate change in the prepare callback with a new flag
"need_update" for the clock reference object, just like others.
- The configure_endpoints() are simplified and folded back into
snd_usb_pcm_prepare().
Fixes: bf6313a0ff76 ("ALSA: usb-audio: Refactor endpoint management")
Fixes: ff878b408a03 ("ALSA: usb-audio: Split endpoint setups for hw_params and prepare")
Reported-by: chihhao chen <chihhao.chen@mediatek.com>
Link: https://lore.kernel.org/r/87e6d6ae69d68dc588ac9acc8c0f24d6188375c3.camel@mediatek.com
Link: https://lore.kernel.org/r/20220901124136.4984-1-tiwai@suse.de
Link: https://bugzilla.kernel.org/show_bug.cgi?id=216500
Link: https://lore.kernel.org/r/20220920181106.4894-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2022-09-20 18:11:06 +00:00
|
|
|
if (subs->sync_endpoint) {
|
|
|
|
ret = snd_usb_endpoint_prepare(chip, subs->sync_endpoint);
|
|
|
|
if (ret < 0)
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = snd_usb_endpoint_prepare(chip, subs->data_endpoint);
|
2012-09-18 16:49:48 +00:00
|
|
|
if (ret < 0)
|
2012-10-12 13:12:55 +00:00
|
|
|
goto unlock;
|
ALSA: usb-audio: Split endpoint setups for hw_params and prepare (take#2)
This is a second attempt to fix the bug appearing on Android with the
recent kernel; the first try was ff878b408a03 and reverted at commit
79764ec772bc.
The details taken from the v1 patch:
One of the former changes for the endpoint management was the more
consistent setup of endpoints at hw_params.
snd_usb_endpoint_configure() is a single function that does the full
setup, and it's called from both PCM hw_params and prepare callbacks.
Although the EP setup at the prepare phase is usually skipped (by
checking need_setup flag), it may be still effective in some cases
like suspend/resume that requires the interface setup again.
As it's a full and single setup, the invocation of
snd_usb_endpoint_configure() includes not only the USB interface setup
but also the buffer release and allocation. OTOH, doing the buffer
release and re-allocation at PCM prepare phase is rather superfluous,
and better to be done only in the hw_params phase.
For those optimizations, this patch splits the endpoint setup to two
phases: snd_usb_endpoint_set_params() and snd_usb_endpoint_prepare(),
to be called from hw_params and from prepare, respectively.
Note that this patch changes the driver operation slightly,
effectively moving the USB interface setup again to PCM prepare stage
instead of hw_params stage, while the buffer allocation and such
initializations are still done at hw_params stage.
And, the change of the USB interface setup timing (moving to prepare)
gave an interesting "fix", too: it was reported that the recent
kernels caused silent output at the beginning on playbacks on some
devices on Android, and this change casually fixed the regression.
It seems that those devices are picky about the sample rate change (or
the interface change?), and don't follow the too immediate rate
changes.
Meanwhile, Android operates the PCM in the following order:
- open, then hw_params with the possibly highest sample rate
- close without prepare
- re-open, hw_params with the normal sample rate
- prepare, and start streaming
This procedure ended up the hw_params twice with different rates, and
because the recent kernel did set up the sample rate twice one and
after, it screwed up the device. OTOH, the earlier kernels didn't set
up the USB interface at hw_params, hence this problem didn't appear.
Now, with this patch, the USB interface setup is again back to the
prepare phase, and it works around the problem automagically.
Although we should address the sample rate problem in a more solid
way in future, let's keep things working as before for now.
***
What's new in the take#2 patch:
- The regression caused by the v1 patch (bko#216500) was due to the
missing check of need_setup flag at hw_params. Now the check is
added, and the snd_usb_endpoint_set_params() call is skipped when
the running EP is re-opened.
- There was another bug in v1 where the clock reference rate wasn't
updated at hw_params phase, which may lead to a lack of the proper
hw constraints when an application doesn't issue the prepare but
only the hw_params call. This patch fixes it as well by tracking
the clock rate change in the prepare callback with a new flag
"need_update" for the clock reference object, just like others.
- The configure_endpoints() are simplified and folded back into
snd_usb_pcm_prepare().
Fixes: bf6313a0ff76 ("ALSA: usb-audio: Refactor endpoint management")
Fixes: ff878b408a03 ("ALSA: usb-audio: Split endpoint setups for hw_params and prepare")
Reported-by: chihhao chen <chihhao.chen@mediatek.com>
Link: https://lore.kernel.org/r/87e6d6ae69d68dc588ac9acc8c0f24d6188375c3.camel@mediatek.com
Link: https://lore.kernel.org/r/20220901124136.4984-1-tiwai@suse.de
Link: https://bugzilla.kernel.org/show_bug.cgi?id=216500
Link: https://lore.kernel.org/r/20220920181106.4894-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2022-09-20 18:11:06 +00:00
|
|
|
else if (ret > 0)
|
|
|
|
snd_usb_set_format_quirk(subs, subs->cur_audiofmt);
|
|
|
|
ret = 0;
|
2012-09-18 16:49:48 +00:00
|
|
|
|
2010-03-04 18:46:13 +00:00
|
|
|
/* reset the pointer */
|
2021-06-01 16:24:54 +00:00
|
|
|
subs->buffer_bytes = frames_to_bytes(runtime, runtime->buffer_size);
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
subs->inflight_bytes = 0;
|
2010-03-04 18:46:13 +00:00
|
|
|
subs->hwptr_done = 0;
|
|
|
|
subs->transfer_done = 0;
|
2011-09-07 00:15:34 +00:00
|
|
|
subs->last_frame_number = 0;
|
ALSA: usb-audio: Reduce latency at playback start, take#2
This is another attempt for the reduction of the latency at the start
of a USB audio playback stream. The first attempt in the commit
9ce650a75a3b caused an unexpected regression (a deadlock with pipewire
usage) and was later reverted by the commit 4b820e167bf6. The devils
are always living in details, of course; the cause of the deadlock was
the call of snd_pcm_period_elapsed() inside prepare_playback_urb()
callback. In the original code, this callback is never called from
the stream lock context as it's driven solely from the URB complete
callback. Along with the movement of the URB submission into the
trigger START, this prepare call may be also executed in the stream
lock context, hence it deadlocked with the another lock in
snd_pcm_period_elapsed(). (Note that this happens only conditionally
with a small period size that matches with the URB buffer length,
which was a reason I overlooked during my tests. Also, the problem
wasn't seen in the capture stream because the capture stream handles
the period-elapsed only at retire callback that isn't executed at the
trigger.)
If it were only about avoiding the deadlock, it'd be possible to use
snd_pcm_period_elapsed_under_stream_lock() as a solution. However, in
general, the period elapsed notification must be sent after the actual
stream start, and replacing the call wouldn't satisfy the pattern.
A better option is to delay the notification after the stream start
procedure finished, instead. In the case of USB framework, one of the
fitting place would be the complete callback of the first URB.
So, as a workaround of the deadlock and the order fixes above, in
addition to the re-applying the changes in the commit 9ce650a75a3,
this patch introduces a new flag indicating the delayed period-elapsed
handling and sets it under the possible deadlock condition
(i.e. prepare callback being called before subs->running is set).
Once when the flag is set, the period-elapsed call is handled at a
later URB complete call instead.
As a reference for the original motivation for the low-latency change,
I cite here again:
| USB-audio driver behaves a bit strangely for the playback stream --
| namely, it starts sending silent packets at PCM prepare state while
| the actual data is submitted at first when the trigger START is
| kicked off. This is a workaround for the behavior where URBs are
| processed too quickly at the beginning. That is, if we start
| submitting URBs at trigger START, the first few URBs will be
| immediately completed, and this would result in the immediate
| period-elapsed calls right after the start, which may confuse
| applications.
|
| OTOH, submitting the data after silent URBs would, of course, result
| in a certain delay of the actual data processing, and this is rather
| more serious problem on modern systems, in practice.
|
| This patch tries to revert the workaround and lets the URB
| submission starting at PCM trigger for the playback again. As far
| as I've tested with various backends (native ALSA, PA, JACK, PW), I
| haven't seen any problems (famous last words :)
|
| Note that the capture stream handling needs no such workaround,
| since the capture is driven per received URB.
Link: https://lore.kernel.org/r/4e71531f-4535-fd46-040e-506a3c256bbd@marcan.st
Link: https://lore.kernel.org/r/s5hbl7li0fe.wl-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/20210707112447.27485-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-07-07 11:24:47 +00:00
|
|
|
subs->period_elapsed_pending = 0;
|
2010-03-04 18:46:13 +00:00
|
|
|
runtime->delay = 0;
|
|
|
|
|
2021-09-29 08:08:39 +00:00
|
|
|
subs->lowlatency_playback = lowlatency_playback_available(runtime, subs);
|
2021-11-19 10:26:29 +00:00
|
|
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
|
2022-12-05 13:21:24 +00:00
|
|
|
!subs->lowlatency_playback) {
|
ALSA: usb-audio: Work around for XRUN with low latency playback
The recent change for low latency playback works in most of test cases
but it turned out still to hit errors on some use cases, most notably
with JACK with small buffer sizes. This is because USB-audio driver
fills up and submits full URBs at the beginning, while the URBs would
return immediately and try to fill more -- that can easily trigger
XRUN. It was more or less expected, but in the small buffer size, the
problem became pretty obvious.
Fixing this behavior properly would require the change of the
fundamental driver design, so it's no trivial task, unfortunately.
Instead, here we work around the problem just by switching back to the
old method when the given configuration is too fragile with the low
latency stream handling. As a threshold, we calculate the total
buffer bytes in all plus one URBs, and check whether it's beyond the
PCM buffer bytes. The one extra URB is needed because XRUN happens at
the next submission after the first round.
Fixes: 307cc9baac5c ("ALSA: usb-audio: Reduce latency at playback start, take#2")
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20210827203311.5987-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-08-27 20:33:11 +00:00
|
|
|
ret = start_endpoints(subs);
|
2022-12-05 13:21:24 +00:00
|
|
|
/* if XRUN happens at starting streams (possibly with implicit
|
|
|
|
* fb case), restart again, but only try once.
|
|
|
|
*/
|
|
|
|
if (ret == -EPIPE && !retry++) {
|
|
|
|
sync_pending_stops(subs);
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
}
|
2012-10-12 13:12:55 +00:00
|
|
|
unlock:
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
snd_usb_unlock_shutdown(chip);
|
2012-10-12 13:12:55 +00:00
|
|
|
return ret;
|
2010-03-04 18:46:13 +00:00
|
|
|
}
|
|
|
|
|
2020-11-23 08:53:18 +00:00
|
|
|
/*
|
|
|
|
* h/w constraints
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HW_CONST_DEBUG
|
|
|
|
#define hwc_debug(fmt, args...) pr_debug(fmt, ##args)
|
|
|
|
#else
|
|
|
|
#define hwc_debug(fmt, args...) do { } while(0)
|
|
|
|
#endif
|
|
|
|
|
2017-08-17 09:15:59 +00:00
|
|
|
static const struct snd_pcm_hardware snd_usb_hardware =
|
2010-03-04 18:46:13 +00:00
|
|
|
{
|
|
|
|
.info = SNDRV_PCM_INFO_MMAP |
|
|
|
|
SNDRV_PCM_INFO_MMAP_VALID |
|
|
|
|
SNDRV_PCM_INFO_BATCH |
|
|
|
|
SNDRV_PCM_INFO_INTERLEAVED |
|
|
|
|
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
|
|
|
SNDRV_PCM_INFO_PAUSE,
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
.channels_min = 1,
|
|
|
|
.channels_max = 256,
|
ALSA: usb-audio: Limit max buffer and period sizes per time
In the previous fix, we increased the max buffer bytes from 1MB to 4MB
so that we can use bigger buffers for the modern HiFi devices with
higher rates, more channels and wider formats. OTOH, extending this
has a concern that too big buffer is allowed for the lower rates, less
channels and narrower formats; when an application tries to allocate
as big buffer as possible, it'll lead to unexpectedly too huge size.
Also, we had a problem about the inconsistent max buffer and period
bytes for the implicit feedback mode when both streams have different
channels. This was fixed by the (relatively complex) patch to reduce
the max buffer and period bytes accordingly.
This is an alternative fix for those, a patch to kill two birds with
one stone (*): instead of increasing the max buffer bytes blindly and
applying the reduction per channels, we simply use the hw constraints
for the buffer and period "time". Meanwhile the max buffer and period
bytes are set unlimited instead.
Since the inconsistency of buffer (and period) bytes comes from the
difference of the channels in the tied streams, as long as we care
only about the buffer (and period) time, it doesn't matter; the buffer
time is same for different channels, although we still allow higher
buffer size. Similarly, this will allow more buffer bytes for HiFi
devices while it also keeps the reasonable size for the legacy
devices, too.
As of this patch, the max period and buffer time are set to 1 and 2
seconds, which should be large enough for all possible use cases.
(*) No animals were harmed in the making of this patch.
Fixes: 98c27add5d96 ("ALSA: usb-audio: Cap upper limits of buffer/period bytes for implicit fb")
Fixes: fee2ec8cceb3 ("ALSA: usb-audio: Increase max buffer size")
Link: https://lore.kernel.org/r/20220412130740.18933-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2022-04-12 13:07:40 +00:00
|
|
|
.buffer_bytes_max = INT_MAX, /* limited by BUFFER_TIME later */
|
2010-03-04 18:46:13 +00:00
|
|
|
.period_bytes_min = 64,
|
ALSA: usb-audio: Limit max buffer and period sizes per time
In the previous fix, we increased the max buffer bytes from 1MB to 4MB
so that we can use bigger buffers for the modern HiFi devices with
higher rates, more channels and wider formats. OTOH, extending this
has a concern that too big buffer is allowed for the lower rates, less
channels and narrower formats; when an application tries to allocate
as big buffer as possible, it'll lead to unexpectedly too huge size.
Also, we had a problem about the inconsistent max buffer and period
bytes for the implicit feedback mode when both streams have different
channels. This was fixed by the (relatively complex) patch to reduce
the max buffer and period bytes accordingly.
This is an alternative fix for those, a patch to kill two birds with
one stone (*): instead of increasing the max buffer bytes blindly and
applying the reduction per channels, we simply use the hw constraints
for the buffer and period "time". Meanwhile the max buffer and period
bytes are set unlimited instead.
Since the inconsistency of buffer (and period) bytes comes from the
difference of the channels in the tied streams, as long as we care
only about the buffer (and period) time, it doesn't matter; the buffer
time is same for different channels, although we still allow higher
buffer size. Similarly, this will allow more buffer bytes for HiFi
devices while it also keeps the reasonable size for the legacy
devices, too.
As of this patch, the max period and buffer time are set to 1 and 2
seconds, which should be large enough for all possible use cases.
(*) No animals were harmed in the making of this patch.
Fixes: 98c27add5d96 ("ALSA: usb-audio: Cap upper limits of buffer/period bytes for implicit fb")
Fixes: fee2ec8cceb3 ("ALSA: usb-audio: Increase max buffer size")
Link: https://lore.kernel.org/r/20220412130740.18933-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2022-04-12 13:07:40 +00:00
|
|
|
.period_bytes_max = INT_MAX, /* limited by PERIOD_TIME later */
|
2010-03-04 18:46:13 +00:00
|
|
|
.periods_min = 2,
|
|
|
|
.periods_max = 1024,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int hw_check_valid_format(struct snd_usb_substream *subs,
|
|
|
|
struct snd_pcm_hw_params *params,
|
2020-11-23 08:53:33 +00:00
|
|
|
const struct audioformat *fp)
|
2010-03-04 18:46:13 +00:00
|
|
|
{
|
|
|
|
struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
|
|
|
|
struct snd_interval *ct = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
|
|
|
|
struct snd_mask *fmts = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
|
|
|
|
struct snd_interval *pt = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME);
|
2010-03-04 18:46:15 +00:00
|
|
|
struct snd_mask check_fmts;
|
2010-03-04 18:46:13 +00:00
|
|
|
unsigned int ptime;
|
|
|
|
|
|
|
|
/* check the format */
|
2010-03-04 18:46:15 +00:00
|
|
|
snd_mask_none(&check_fmts);
|
|
|
|
check_fmts.bits[0] = (u32)fp->formats;
|
|
|
|
check_fmts.bits[1] = (u32)(fp->formats >> 32);
|
|
|
|
snd_mask_intersect(&check_fmts, fmts);
|
|
|
|
if (snd_mask_empty(&check_fmts)) {
|
2021-01-11 08:16:11 +00:00
|
|
|
hwc_debug(" > check: no supported format 0x%llx\n", fp->formats);
|
2010-03-04 18:46:13 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* check the channels */
|
|
|
|
if (fp->channels < ct->min || fp->channels > ct->max) {
|
|
|
|
hwc_debug(" > check: no valid channels %d (%d/%d)\n", fp->channels, ct->min, ct->max);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* check the rate is within the range */
|
|
|
|
if (fp->rate_min > it->max || (fp->rate_min == it->max && it->openmax)) {
|
|
|
|
hwc_debug(" > check: rate_min %d > max %d\n", fp->rate_min, it->max);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (fp->rate_max < it->min || (fp->rate_max == it->min && it->openmin)) {
|
|
|
|
hwc_debug(" > check: rate_max %d < min %d\n", fp->rate_max, it->min);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* check whether the period time is >= the data packet interval */
|
2012-10-12 13:12:55 +00:00
|
|
|
if (subs->speed != USB_SPEED_FULL) {
|
2010-03-04 18:46:13 +00:00
|
|
|
ptime = 125 * (1 << fp->datainterval);
|
|
|
|
if (ptime > pt->max || (ptime == pt->max && pt->openmax)) {
|
|
|
|
hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-11-23 08:53:17 +00:00
|
|
|
static int apply_hw_params_minmax(struct snd_interval *it, unsigned int rmin,
|
|
|
|
unsigned int rmax)
|
|
|
|
{
|
|
|
|
int changed;
|
|
|
|
|
|
|
|
if (rmin > rmax) {
|
|
|
|
hwc_debug(" --> get empty\n");
|
|
|
|
it->empty = 1;
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
changed = 0;
|
|
|
|
if (it->min < rmin) {
|
|
|
|
it->min = rmin;
|
|
|
|
it->openmin = 0;
|
|
|
|
changed = 1;
|
|
|
|
}
|
|
|
|
if (it->max > rmax) {
|
|
|
|
it->max = rmax;
|
|
|
|
it->openmax = 0;
|
|
|
|
changed = 1;
|
|
|
|
}
|
|
|
|
if (snd_interval_checkempty(it)) {
|
|
|
|
it->empty = 1;
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
hwc_debug(" --> (%d, %d) (changed = %d)\n", it->min, it->max, changed);
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
2023-01-02 17:07:59 +00:00
|
|
|
/* get the specified endpoint object that is being used by other streams
|
|
|
|
* (i.e. the parameter is locked)
|
|
|
|
*/
|
|
|
|
static const struct snd_usb_endpoint *
|
|
|
|
get_endpoint_in_use(struct snd_usb_audio *chip, int endpoint,
|
|
|
|
const struct snd_usb_endpoint *ref_ep)
|
|
|
|
{
|
|
|
|
const struct snd_usb_endpoint *ep;
|
|
|
|
|
|
|
|
ep = snd_usb_get_endpoint(chip, endpoint);
|
|
|
|
if (ep && ep->cur_audiofmt && (ep != ref_ep || ep->opened > 1))
|
|
|
|
return ep;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-03-04 18:46:13 +00:00
|
|
|
static int hw_rule_rate(struct snd_pcm_hw_params *params,
|
|
|
|
struct snd_pcm_hw_rule *rule)
|
|
|
|
{
|
|
|
|
struct snd_usb_substream *subs = rule->private;
|
2021-09-29 08:08:36 +00:00
|
|
|
struct snd_usb_audio *chip = subs->stream->chip;
|
2023-01-02 17:07:59 +00:00
|
|
|
const struct snd_usb_endpoint *ep;
|
2020-11-23 08:53:33 +00:00
|
|
|
const struct audioformat *fp;
|
2010-03-04 18:46:13 +00:00
|
|
|
struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
|
2020-11-23 08:53:07 +00:00
|
|
|
unsigned int rmin, rmax, r;
|
|
|
|
int i;
|
2010-03-04 18:46:13 +00:00
|
|
|
|
|
|
|
hwc_debug("hw_rule_rate: (%d,%d)\n", it->min, it->max);
|
2020-11-23 08:53:07 +00:00
|
|
|
rmin = UINT_MAX;
|
|
|
|
rmax = 0;
|
2013-04-03 21:18:49 +00:00
|
|
|
list_for_each_entry(fp, &subs->fmt_list, list) {
|
2010-03-04 18:46:13 +00:00
|
|
|
if (!hw_check_valid_format(subs, params, fp))
|
|
|
|
continue;
|
2023-01-02 17:07:59 +00:00
|
|
|
|
|
|
|
ep = get_endpoint_in_use(chip, fp->endpoint,
|
|
|
|
subs->data_endpoint);
|
|
|
|
if (ep) {
|
|
|
|
hwc_debug("rate limit %d for ep#%x\n",
|
|
|
|
ep->cur_rate, fp->endpoint);
|
|
|
|
rmin = min(rmin, ep->cur_rate);
|
|
|
|
rmax = max(rmax, ep->cur_rate);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fp->implicit_fb) {
|
|
|
|
ep = get_endpoint_in_use(chip, fp->sync_ep,
|
|
|
|
subs->sync_endpoint);
|
|
|
|
if (ep) {
|
|
|
|
hwc_debug("rate limit %d for sync_ep#%x\n",
|
|
|
|
ep->cur_rate, fp->sync_ep);
|
|
|
|
rmin = min(rmin, ep->cur_rate);
|
|
|
|
rmax = max(rmax, ep->cur_rate);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-29 08:08:36 +00:00
|
|
|
r = snd_usb_endpoint_get_clock_rate(chip, fp->clock);
|
|
|
|
if (r > 0) {
|
|
|
|
if (!snd_interval_test(it, r))
|
|
|
|
continue;
|
|
|
|
rmin = min(rmin, r);
|
|
|
|
rmax = max(rmax, r);
|
|
|
|
continue;
|
|
|
|
}
|
2020-11-23 08:53:07 +00:00
|
|
|
if (fp->rate_table && fp->nr_rates) {
|
|
|
|
for (i = 0; i < fp->nr_rates; i++) {
|
|
|
|
r = fp->rate_table[i];
|
|
|
|
if (!snd_interval_test(it, r))
|
|
|
|
continue;
|
|
|
|
rmin = min(rmin, r);
|
|
|
|
rmax = max(rmax, r);
|
|
|
|
}
|
2010-03-04 18:46:13 +00:00
|
|
|
} else {
|
2020-11-23 08:53:07 +00:00
|
|
|
rmin = min(rmin, fp->rate_min);
|
|
|
|
rmax = max(rmax, fp->rate_max);
|
2010-03-04 18:46:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-23 08:53:17 +00:00
|
|
|
return apply_hw_params_minmax(it, rmin, rmax);
|
2010-03-04 18:46:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int hw_rule_channels(struct snd_pcm_hw_params *params,
|
|
|
|
struct snd_pcm_hw_rule *rule)
|
|
|
|
{
|
|
|
|
struct snd_usb_substream *subs = rule->private;
|
2020-11-23 08:53:33 +00:00
|
|
|
const struct audioformat *fp;
|
2010-03-04 18:46:13 +00:00
|
|
|
struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
|
|
|
|
unsigned int rmin, rmax;
|
|
|
|
|
|
|
|
hwc_debug("hw_rule_channels: (%d,%d)\n", it->min, it->max);
|
2020-11-23 08:53:17 +00:00
|
|
|
rmin = UINT_MAX;
|
|
|
|
rmax = 0;
|
2013-04-03 21:18:49 +00:00
|
|
|
list_for_each_entry(fp, &subs->fmt_list, list) {
|
2010-03-04 18:46:13 +00:00
|
|
|
if (!hw_check_valid_format(subs, params, fp))
|
|
|
|
continue;
|
2020-11-23 08:53:17 +00:00
|
|
|
rmin = min(rmin, fp->channels);
|
|
|
|
rmax = max(rmax, fp->channels);
|
2010-03-04 18:46:13 +00:00
|
|
|
}
|
|
|
|
|
2020-11-23 08:53:17 +00:00
|
|
|
return apply_hw_params_minmax(it, rmin, rmax);
|
2010-03-04 18:46:13 +00:00
|
|
|
}
|
|
|
|
|
2021-01-11 08:16:11 +00:00
|
|
|
static int apply_hw_params_format_bits(struct snd_mask *fmt, u64 fbits)
|
2010-03-04 18:46:13 +00:00
|
|
|
{
|
|
|
|
u32 oldbits[2];
|
|
|
|
int changed;
|
|
|
|
|
|
|
|
oldbits[0] = fmt->bits[0];
|
|
|
|
oldbits[1] = fmt->bits[1];
|
|
|
|
fmt->bits[0] &= (u32)fbits;
|
|
|
|
fmt->bits[1] &= (u32)(fbits >> 32);
|
|
|
|
if (!fmt->bits[0] && !fmt->bits[1]) {
|
|
|
|
hwc_debug(" --> get empty\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
changed = (oldbits[0] != fmt->bits[0] || oldbits[1] != fmt->bits[1]);
|
|
|
|
hwc_debug(" --> %x:%x (changed = %d)\n", fmt->bits[0], fmt->bits[1], changed);
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
2021-01-11 08:16:11 +00:00
|
|
|
static int hw_rule_format(struct snd_pcm_hw_params *params,
|
|
|
|
struct snd_pcm_hw_rule *rule)
|
|
|
|
{
|
|
|
|
struct snd_usb_substream *subs = rule->private;
|
2023-01-02 17:07:59 +00:00
|
|
|
struct snd_usb_audio *chip = subs->stream->chip;
|
|
|
|
const struct snd_usb_endpoint *ep;
|
2021-01-11 08:16:11 +00:00
|
|
|
const struct audioformat *fp;
|
|
|
|
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
|
|
|
|
u64 fbits;
|
|
|
|
|
|
|
|
hwc_debug("hw_rule_format: %x:%x\n", fmt->bits[0], fmt->bits[1]);
|
|
|
|
fbits = 0;
|
|
|
|
list_for_each_entry(fp, &subs->fmt_list, list) {
|
|
|
|
if (!hw_check_valid_format(subs, params, fp))
|
|
|
|
continue;
|
2023-01-02 17:07:59 +00:00
|
|
|
|
|
|
|
ep = get_endpoint_in_use(chip, fp->endpoint,
|
|
|
|
subs->data_endpoint);
|
|
|
|
if (ep) {
|
|
|
|
hwc_debug("format limit %d for ep#%x\n",
|
|
|
|
ep->cur_format, fp->endpoint);
|
|
|
|
fbits |= pcm_format_to_bits(ep->cur_format);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fp->implicit_fb) {
|
|
|
|
ep = get_endpoint_in_use(chip, fp->sync_ep,
|
|
|
|
subs->sync_endpoint);
|
|
|
|
if (ep) {
|
|
|
|
hwc_debug("format limit %d for sync_ep#%x\n",
|
|
|
|
ep->cur_format, fp->sync_ep);
|
|
|
|
fbits |= pcm_format_to_bits(ep->cur_format);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-11 08:16:11 +00:00
|
|
|
fbits |= fp->formats;
|
|
|
|
}
|
|
|
|
return apply_hw_params_format_bits(fmt, fbits);
|
|
|
|
}
|
|
|
|
|
2010-03-04 18:46:13 +00:00
|
|
|
static int hw_rule_period_time(struct snd_pcm_hw_params *params,
|
|
|
|
struct snd_pcm_hw_rule *rule)
|
|
|
|
{
|
|
|
|
struct snd_usb_substream *subs = rule->private;
|
2020-11-23 08:53:33 +00:00
|
|
|
const struct audioformat *fp;
|
2010-03-04 18:46:13 +00:00
|
|
|
struct snd_interval *it;
|
|
|
|
unsigned char min_datainterval;
|
|
|
|
unsigned int pmin;
|
|
|
|
|
|
|
|
it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME);
|
|
|
|
hwc_debug("hw_rule_period_time: (%u,%u)\n", it->min, it->max);
|
|
|
|
min_datainterval = 0xff;
|
|
|
|
list_for_each_entry(fp, &subs->fmt_list, list) {
|
|
|
|
if (!hw_check_valid_format(subs, params, fp))
|
|
|
|
continue;
|
|
|
|
min_datainterval = min(min_datainterval, fp->datainterval);
|
|
|
|
}
|
|
|
|
if (min_datainterval == 0xff) {
|
2010-07-12 15:15:44 +00:00
|
|
|
hwc_debug(" --> get empty\n");
|
2010-03-04 18:46:13 +00:00
|
|
|
it->empty = 1;
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
pmin = 125 * (1 << min_datainterval);
|
2020-11-23 08:53:17 +00:00
|
|
|
|
|
|
|
return apply_hw_params_minmax(it, pmin, UINT_MAX);
|
2010-03-04 18:46:13 +00:00
|
|
|
}
|
|
|
|
|
2023-01-02 17:07:59 +00:00
|
|
|
/* additional hw constraints for implicit feedback mode */
|
|
|
|
static int hw_rule_period_size_implicit_fb(struct snd_pcm_hw_params *params,
|
|
|
|
struct snd_pcm_hw_rule *rule)
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
{
|
2023-01-02 17:07:59 +00:00
|
|
|
struct snd_usb_substream *subs = rule->private;
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
struct snd_usb_audio *chip = subs->stream->chip;
|
2020-11-23 08:53:33 +00:00
|
|
|
const struct audioformat *fp;
|
2021-01-11 08:16:11 +00:00
|
|
|
const struct snd_usb_endpoint *ep;
|
2023-01-02 17:07:59 +00:00
|
|
|
struct snd_interval *it;
|
|
|
|
unsigned int rmin, rmax;
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
|
2023-01-02 17:07:59 +00:00
|
|
|
it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
|
|
|
|
hwc_debug("hw_rule_period_size: (%u,%u)\n", it->min, it->max);
|
|
|
|
rmin = UINT_MAX;
|
|
|
|
rmax = 0;
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
list_for_each_entry(fp, &subs->fmt_list, list) {
|
2023-01-02 17:07:59 +00:00
|
|
|
if (!hw_check_valid_format(subs, params, fp))
|
|
|
|
continue;
|
|
|
|
ep = get_endpoint_in_use(chip, fp->endpoint,
|
|
|
|
subs->data_endpoint);
|
|
|
|
if (ep) {
|
|
|
|
hwc_debug("period size limit %d for ep#%x\n",
|
|
|
|
ep->cur_period_frames, fp->endpoint);
|
|
|
|
rmin = min(rmin, ep->cur_period_frames);
|
|
|
|
rmax = max(rmax, ep->cur_period_frames);
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
continue;
|
2023-01-02 17:07:58 +00:00
|
|
|
}
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
|
2023-01-02 17:07:59 +00:00
|
|
|
if (fp->implicit_fb) {
|
|
|
|
ep = get_endpoint_in_use(chip, fp->sync_ep,
|
|
|
|
subs->sync_endpoint);
|
|
|
|
if (ep) {
|
|
|
|
hwc_debug("period size limit %d for sync_ep#%x\n",
|
|
|
|
ep->cur_period_frames, fp->sync_ep);
|
|
|
|
rmin = min(rmin, ep->cur_period_frames);
|
|
|
|
rmax = max(rmax, ep->cur_period_frames);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-11 08:16:11 +00:00
|
|
|
|
2023-01-02 17:07:59 +00:00
|
|
|
if (!rmax)
|
|
|
|
return 0; /* no limit by implicit fb */
|
|
|
|
return apply_hw_params_minmax(it, rmin, rmax);
|
2021-01-11 08:16:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int hw_rule_periods_implicit_fb(struct snd_pcm_hw_params *params,
|
|
|
|
struct snd_pcm_hw_rule *rule)
|
|
|
|
{
|
|
|
|
struct snd_usb_substream *subs = rule->private;
|
2023-01-02 17:07:59 +00:00
|
|
|
struct snd_usb_audio *chip = subs->stream->chip;
|
|
|
|
const struct audioformat *fp;
|
2021-01-11 08:16:11 +00:00
|
|
|
const struct snd_usb_endpoint *ep;
|
|
|
|
struct snd_interval *it;
|
2023-01-02 17:07:59 +00:00
|
|
|
unsigned int rmin, rmax;
|
2021-01-11 08:16:11 +00:00
|
|
|
|
|
|
|
it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIODS);
|
2023-01-02 17:07:59 +00:00
|
|
|
hwc_debug("hw_rule_periods: (%u,%u)\n", it->min, it->max);
|
|
|
|
rmin = UINT_MAX;
|
|
|
|
rmax = 0;
|
|
|
|
list_for_each_entry(fp, &subs->fmt_list, list) {
|
|
|
|
if (!hw_check_valid_format(subs, params, fp))
|
|
|
|
continue;
|
|
|
|
ep = get_endpoint_in_use(chip, fp->endpoint,
|
|
|
|
subs->data_endpoint);
|
|
|
|
if (ep) {
|
|
|
|
hwc_debug("periods limit %d for ep#%x\n",
|
|
|
|
ep->cur_buffer_periods, fp->endpoint);
|
|
|
|
rmin = min(rmin, ep->cur_buffer_periods);
|
|
|
|
rmax = max(rmax, ep->cur_buffer_periods);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fp->implicit_fb) {
|
|
|
|
ep = get_endpoint_in_use(chip, fp->sync_ep,
|
|
|
|
subs->sync_endpoint);
|
|
|
|
if (ep) {
|
|
|
|
hwc_debug("periods limit %d for sync_ep#%x\n",
|
|
|
|
ep->cur_buffer_periods, fp->sync_ep);
|
|
|
|
rmin = min(rmin, ep->cur_buffer_periods);
|
|
|
|
rmax = max(rmax, ep->cur_buffer_periods);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rmax)
|
|
|
|
return 0; /* no limit by implicit fb */
|
|
|
|
return apply_hw_params_minmax(it, rmin, rmax);
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
}
|
2010-03-04 18:46:13 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* set up the runtime hardware information.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs)
|
|
|
|
{
|
2020-11-23 08:53:33 +00:00
|
|
|
const struct audioformat *fp;
|
2010-03-04 18:46:13 +00:00
|
|
|
unsigned int pt, ptmin;
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
int param_period_time_if_needed = -1;
|
2010-03-04 18:46:13 +00:00
|
|
|
int err;
|
|
|
|
|
|
|
|
runtime->hw.formats = subs->formats;
|
|
|
|
|
|
|
|
runtime->hw.rate_min = 0x7fffffff;
|
|
|
|
runtime->hw.rate_max = 0;
|
|
|
|
runtime->hw.channels_min = 256;
|
|
|
|
runtime->hw.channels_max = 0;
|
|
|
|
runtime->hw.rates = 0;
|
|
|
|
ptmin = UINT_MAX;
|
|
|
|
/* check min/max rates and channels */
|
2013-04-03 21:18:49 +00:00
|
|
|
list_for_each_entry(fp, &subs->fmt_list, list) {
|
2010-03-04 18:46:13 +00:00
|
|
|
runtime->hw.rates |= fp->rates;
|
|
|
|
if (runtime->hw.rate_min > fp->rate_min)
|
|
|
|
runtime->hw.rate_min = fp->rate_min;
|
|
|
|
if (runtime->hw.rate_max < fp->rate_max)
|
|
|
|
runtime->hw.rate_max = fp->rate_max;
|
|
|
|
if (runtime->hw.channels_min > fp->channels)
|
|
|
|
runtime->hw.channels_min = fp->channels;
|
|
|
|
if (runtime->hw.channels_max < fp->channels)
|
|
|
|
runtime->hw.channels_max = fp->channels;
|
|
|
|
if (fp->fmt_type == UAC_FORMAT_TYPE_II && fp->frame_size > 0) {
|
|
|
|
/* FIXME: there might be more than one audio formats... */
|
|
|
|
runtime->hw.period_bytes_min = runtime->hw.period_bytes_max =
|
|
|
|
fp->frame_size;
|
|
|
|
}
|
|
|
|
pt = 125 * (1 << fp->datainterval);
|
|
|
|
ptmin = min(ptmin, pt);
|
|
|
|
}
|
|
|
|
|
|
|
|
param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME;
|
2012-10-12 13:12:55 +00:00
|
|
|
if (subs->speed == USB_SPEED_FULL)
|
2010-03-04 18:46:13 +00:00
|
|
|
/* full speed devices have fixed data packet interval */
|
|
|
|
ptmin = 1000;
|
|
|
|
if (ptmin == 1000)
|
|
|
|
/* if period time doesn't go below 1 ms, no rules needed */
|
|
|
|
param_period_time_if_needed = -1;
|
2018-05-27 13:09:15 +00:00
|
|
|
|
|
|
|
err = snd_pcm_hw_constraint_minmax(runtime,
|
|
|
|
SNDRV_PCM_HW_PARAM_PERIOD_TIME,
|
|
|
|
ptmin, UINT_MAX);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
|
|
|
hw_rule_rate, subs,
|
ALSA: usb-audio: Fix hw constraints dependencies
Since the recent refactoring, it's been reported that some USB-audio
devices (typically webcams) are no longer detected properly by
PulseAudio. The debug session revealed that it's failing at probing
by PA to try the sample rate 44.1kHz while the device has discrete
sample rates other than 44.1kHz. But the puzzle was that arecord
works as is, and some other devices with the discrete rates work,
either.
After all, this turned out to be the lack of the dependencies in a few
hw constraint rules: snd_pcm_hw_rule_add() has the (variable)
arguments specifying the dependent parameters, and some functions
didn't set the target parameter itself as the dependencies. This
resulted in an invalid parameter that could be generated only in a
certain call pattern. This bug itself has been present in the code,
but it didn't trigger errors just because the rules were casually
avoiding such a corner case. After the recent refactoring and
cleanup, however, the hw constraints work "as expected", and the
problem surfaced now.
For fixing the problem above, this patch adds the missing dependent
parameters to each snd_pcm_hw_rule() call.
Fixes: bc4e94aa8e72 ("ALSA: usb-audio: Handle discrete rates properly in hw constraints")
BugLink: http://bugzilla.opensuse.org/show_bug.cgi?id=1181014
Link: https://lore.kernel.org/r/20210120204554.30177-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-01-20 20:45:54 +00:00
|
|
|
SNDRV_PCM_HW_PARAM_RATE,
|
2018-05-27 13:09:15 +00:00
|
|
|
SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
SNDRV_PCM_HW_PARAM_CHANNELS,
|
|
|
|
param_period_time_if_needed,
|
|
|
|
-1);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
ALSA: usb-audio: Add hw constraint for implicit fb sync
In the current code, there is no check at the stream open time whether
the endpoint is being already used by others. In the normal
operations, this shouldn't happen, but in the case of the implicit
feedback mode, it's a common problem with the full duplex operation,
because the capture stream is always opened by the playback stream as
an implicit sync source.
Although we recently introduced the check of such a conflict of
parameters at the PCM hw_params time, it doesn't give any hint at the
hw_params itself and just gives the error. This isn't quite
comfortable, and it caused problems on many applications.
This patch attempts to make the parameter handling easier by
introducing the strict hw constraint matching with the counterpart
stream that is being used. That said, when an implicit feedback
playback stream is running before a capture stream is opened, the
capture stream carries the PCM hw-constraint to allow only the same
sample rate, format, periods and period frames as the running playback
stream. If not opened or there is no conflict of endpoints, the
behavior remains as same as before.
Note that this kind of "weak link" should work for most cases, but
this is no concrete solution; e.g. if an application changes the hw
params multiple times while another stream is opened, this would lead
to inconsistencies.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-11-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:16 +00:00
|
|
|
|
2018-05-27 13:09:15 +00:00
|
|
|
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
|
|
|
hw_rule_channels, subs,
|
ALSA: usb-audio: Fix hw constraints dependencies
Since the recent refactoring, it's been reported that some USB-audio
devices (typically webcams) are no longer detected properly by
PulseAudio. The debug session revealed that it's failing at probing
by PA to try the sample rate 44.1kHz while the device has discrete
sample rates other than 44.1kHz. But the puzzle was that arecord
works as is, and some other devices with the discrete rates work,
either.
After all, this turned out to be the lack of the dependencies in a few
hw constraint rules: snd_pcm_hw_rule_add() has the (variable)
arguments specifying the dependent parameters, and some functions
didn't set the target parameter itself as the dependencies. This
resulted in an invalid parameter that could be generated only in a
certain call pattern. This bug itself has been present in the code,
but it didn't trigger errors just because the rules were casually
avoiding such a corner case. After the recent refactoring and
cleanup, however, the hw constraints work "as expected", and the
problem surfaced now.
For fixing the problem above, this patch adds the missing dependent
parameters to each snd_pcm_hw_rule() call.
Fixes: bc4e94aa8e72 ("ALSA: usb-audio: Handle discrete rates properly in hw constraints")
BugLink: http://bugzilla.opensuse.org/show_bug.cgi?id=1181014
Link: https://lore.kernel.org/r/20210120204554.30177-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-01-20 20:45:54 +00:00
|
|
|
SNDRV_PCM_HW_PARAM_CHANNELS,
|
2018-05-27 13:09:15 +00:00
|
|
|
SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
SNDRV_PCM_HW_PARAM_RATE,
|
|
|
|
param_period_time_if_needed,
|
|
|
|
-1);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
hw_rule_format, subs,
|
ALSA: usb-audio: Fix hw constraints dependencies
Since the recent refactoring, it's been reported that some USB-audio
devices (typically webcams) are no longer detected properly by
PulseAudio. The debug session revealed that it's failing at probing
by PA to try the sample rate 44.1kHz while the device has discrete
sample rates other than 44.1kHz. But the puzzle was that arecord
works as is, and some other devices with the discrete rates work,
either.
After all, this turned out to be the lack of the dependencies in a few
hw constraint rules: snd_pcm_hw_rule_add() has the (variable)
arguments specifying the dependent parameters, and some functions
didn't set the target parameter itself as the dependencies. This
resulted in an invalid parameter that could be generated only in a
certain call pattern. This bug itself has been present in the code,
but it didn't trigger errors just because the rules were casually
avoiding such a corner case. After the recent refactoring and
cleanup, however, the hw constraints work "as expected", and the
problem surfaced now.
For fixing the problem above, this patch adds the missing dependent
parameters to each snd_pcm_hw_rule() call.
Fixes: bc4e94aa8e72 ("ALSA: usb-audio: Handle discrete rates properly in hw constraints")
BugLink: http://bugzilla.opensuse.org/show_bug.cgi?id=1181014
Link: https://lore.kernel.org/r/20210120204554.30177-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-01-20 20:45:54 +00:00
|
|
|
SNDRV_PCM_HW_PARAM_FORMAT,
|
2018-05-27 13:09:15 +00:00
|
|
|
SNDRV_PCM_HW_PARAM_RATE,
|
|
|
|
SNDRV_PCM_HW_PARAM_CHANNELS,
|
|
|
|
param_period_time_if_needed,
|
|
|
|
-1);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2010-03-04 18:46:13 +00:00
|
|
|
if (param_period_time_if_needed >= 0) {
|
|
|
|
err = snd_pcm_hw_rule_add(runtime, 0,
|
|
|
|
SNDRV_PCM_HW_PARAM_PERIOD_TIME,
|
|
|
|
hw_rule_period_time, subs,
|
|
|
|
SNDRV_PCM_HW_PARAM_FORMAT,
|
|
|
|
SNDRV_PCM_HW_PARAM_CHANNELS,
|
|
|
|
SNDRV_PCM_HW_PARAM_RATE,
|
|
|
|
-1);
|
|
|
|
if (err < 0)
|
2018-05-27 13:09:15 +00:00
|
|
|
return err;
|
2010-03-04 18:46:13 +00:00
|
|
|
}
|
2011-03-11 13:51:12 +00:00
|
|
|
|
ALSA: usb-audio: Limit max buffer and period sizes per time
In the previous fix, we increased the max buffer bytes from 1MB to 4MB
so that we can use bigger buffers for the modern HiFi devices with
higher rates, more channels and wider formats. OTOH, extending this
has a concern that too big buffer is allowed for the lower rates, less
channels and narrower formats; when an application tries to allocate
as big buffer as possible, it'll lead to unexpectedly too huge size.
Also, we had a problem about the inconsistent max buffer and period
bytes for the implicit feedback mode when both streams have different
channels. This was fixed by the (relatively complex) patch to reduce
the max buffer and period bytes accordingly.
This is an alternative fix for those, a patch to kill two birds with
one stone (*): instead of increasing the max buffer bytes blindly and
applying the reduction per channels, we simply use the hw constraints
for the buffer and period "time". Meanwhile the max buffer and period
bytes are set unlimited instead.
Since the inconsistency of buffer (and period) bytes comes from the
difference of the channels in the tied streams, as long as we care
only about the buffer (and period) time, it doesn't matter; the buffer
time is same for different channels, although we still allow higher
buffer size. Similarly, this will allow more buffer bytes for HiFi
devices while it also keeps the reasonable size for the legacy
devices, too.
As of this patch, the max period and buffer time are set to 1 and 2
seconds, which should be large enough for all possible use cases.
(*) No animals were harmed in the making of this patch.
Fixes: 98c27add5d96 ("ALSA: usb-audio: Cap upper limits of buffer/period bytes for implicit fb")
Fixes: fee2ec8cceb3 ("ALSA: usb-audio: Increase max buffer size")
Link: https://lore.kernel.org/r/20220412130740.18933-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2022-04-12 13:07:40 +00:00
|
|
|
/* set max period and buffer sizes for 1 and 2 seconds, respectively */
|
|
|
|
err = snd_pcm_hw_constraint_minmax(runtime,
|
|
|
|
SNDRV_PCM_HW_PARAM_PERIOD_TIME,
|
|
|
|
0, 1000000);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
err = snd_pcm_hw_constraint_minmax(runtime,
|
|
|
|
SNDRV_PCM_HW_PARAM_BUFFER_TIME,
|
|
|
|
0, 2000000);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
2021-01-11 08:16:11 +00:00
|
|
|
/* additional hw constraints for implicit fb */
|
|
|
|
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
|
|
|
|
hw_rule_period_size_implicit_fb, subs,
|
|
|
|
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS,
|
|
|
|
hw_rule_periods_implicit_fb, subs,
|
|
|
|
SNDRV_PCM_HW_PARAM_PERIODS, -1);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
2021-10-07 08:35:28 +00:00
|
|
|
list_for_each_entry(fp, &subs->fmt_list, list) {
|
|
|
|
if (fp->implicit_fb) {
|
|
|
|
runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-23 08:53:15 +00:00
|
|
|
return 0;
|
2010-03-04 18:46:13 +00:00
|
|
|
}
|
|
|
|
|
2018-05-27 11:59:03 +00:00
|
|
|
static int snd_usb_pcm_open(struct snd_pcm_substream *substream)
|
2010-03-04 18:46:13 +00:00
|
|
|
{
|
2018-05-27 11:59:03 +00:00
|
|
|
int direction = substream->stream;
|
2010-03-04 18:46:13 +00:00
|
|
|
struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
|
|
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
|
|
struct snd_usb_substream *subs = &as->substream[direction];
|
media: sound/usb: Use Media Controller API to share media resources
Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.
Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.
Change the ALSA driver to use the Media Controller API to share media
resources with DVB, and V4L2 drivers on a AU0828 media device.
The Media Controller specific initialization is done after sound card is
registered. ALSA creates Media interface and entity function graph nodes
for Control, Mixer, PCM Playback, and PCM Capture devices.
snd_usb_hw_params() will call Media Controller enable source handler
interface to request the media resource. If resource request is granted,
it will release it from snd_usb_hw_free(). If resource is busy, -EBUSY is
returned.
Media specific cleanup is done in usb_audio_disconnect().
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Shuah Khan <shuah@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2019-04-02 00:40:22 +00:00
|
|
|
int ret;
|
2010-03-04 18:46:13 +00:00
|
|
|
|
|
|
|
runtime->hw = snd_usb_hardware;
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
/* need an explicit sync to catch applptr update in low-latency mode */
|
|
|
|
if (direction == SNDRV_PCM_STREAM_PLAYBACK &&
|
|
|
|
as->chip->lowlatency)
|
2021-10-11 10:36:50 +00:00
|
|
|
runtime->hw.info |= SNDRV_PCM_INFO_SYNC_APPLPTR;
|
2010-03-04 18:46:13 +00:00
|
|
|
runtime->private_data = subs;
|
|
|
|
subs->pcm_substream = substream;
|
2011-03-11 13:51:12 +00:00
|
|
|
/* runtime PM is also done there */
|
2013-04-16 16:01:38 +00:00
|
|
|
|
|
|
|
/* initialize DSD/DOP context */
|
|
|
|
subs->dsd_dop.byte_idx = 0;
|
|
|
|
subs->dsd_dop.channel = 0;
|
|
|
|
subs->dsd_dop.marker = 1;
|
|
|
|
|
media: sound/usb: Use Media Controller API to share media resources
Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.
Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.
Change the ALSA driver to use the Media Controller API to share media
resources with DVB, and V4L2 drivers on a AU0828 media device.
The Media Controller specific initialization is done after sound card is
registered. ALSA creates Media interface and entity function graph nodes
for Control, Mixer, PCM Playback, and PCM Capture devices.
snd_usb_hw_params() will call Media Controller enable source handler
interface to request the media resource. If resource request is granted,
it will release it from snd_usb_hw_free(). If resource is busy, -EBUSY is
returned.
Media specific cleanup is done in usb_audio_disconnect().
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Shuah Khan <shuah@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2019-04-02 00:40:22 +00:00
|
|
|
ret = setup_hw_info(runtime, subs);
|
2020-11-23 08:53:15 +00:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = snd_usb_autoresume(subs->stream->chip);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
ret = snd_media_stream_init(subs, as->pcm, direction);
|
|
|
|
if (ret < 0)
|
|
|
|
snd_usb_autosuspend(subs->stream->chip);
|
media: sound/usb: Use Media Controller API to share media resources
Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.
Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.
Change the ALSA driver to use the Media Controller API to share media
resources with DVB, and V4L2 drivers on a AU0828 media device.
The Media Controller specific initialization is done after sound card is
registered. ALSA creates Media interface and entity function graph nodes
for Control, Mixer, PCM Playback, and PCM Capture devices.
snd_usb_hw_params() will call Media Controller enable source handler
interface to request the media resource. If resource request is granted,
it will release it from snd_usb_hw_free(). If resource is busy, -EBUSY is
returned.
Media specific cleanup is done in usb_audio_disconnect().
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Shuah Khan <shuah@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2019-04-02 00:40:22 +00:00
|
|
|
return ret;
|
2010-03-04 18:46:13 +00:00
|
|
|
}
|
|
|
|
|
2018-05-27 11:59:03 +00:00
|
|
|
static int snd_usb_pcm_close(struct snd_pcm_substream *substream)
|
2010-03-04 18:46:13 +00:00
|
|
|
{
|
2018-05-27 11:59:03 +00:00
|
|
|
int direction = substream->stream;
|
2010-03-04 18:46:13 +00:00
|
|
|
struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
|
|
|
|
struct snd_usb_substream *subs = &as->substream[direction];
|
2018-07-31 12:28:45 +00:00
|
|
|
int ret;
|
2010-03-04 18:46:13 +00:00
|
|
|
|
media: sound/usb: Use Media Controller API to share media resources
Media Device Allocator API to allows multiple drivers share a media device.
This API solves a very common use-case for media devices where one physical
device (an USB stick) provides both audio and video. When such media device
exposes a standard USB Audio class, a proprietary Video class, two or more
independent drivers will share a single physical USB bridge. In such cases,
it is necessary to coordinate access to the shared resource.
Using this API, drivers can allocate a media device with the shared struct
device as the key. Once the media device is allocated by a driver, other
drivers can get a reference to it. The media device is released when all
the references are released.
Change the ALSA driver to use the Media Controller API to share media
resources with DVB, and V4L2 drivers on a AU0828 media device.
The Media Controller specific initialization is done after sound card is
registered. ALSA creates Media interface and entity function graph nodes
for Control, Mixer, PCM Playback, and PCM Capture devices.
snd_usb_hw_params() will call Media Controller enable source handler
interface to request the media resource. If resource request is granted,
it will release it from snd_usb_hw_free(). If resource is busy, -EBUSY is
returned.
Media specific cleanup is done in usb_audio_disconnect().
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Shuah Khan <shuah@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2019-04-02 00:40:22 +00:00
|
|
|
snd_media_stop_pipeline(subs);
|
2012-07-12 11:08:40 +00:00
|
|
|
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
if (!snd_usb_lock_shutdown(subs->stream->chip)) {
|
2018-07-31 12:28:45 +00:00
|
|
|
ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D1);
|
ALSA: usb-audio: Avoid nested autoresume calls
After the recent fix of runtime PM for USB-audio driver, we got a
lockdep warning like:
=============================================
[ INFO: possible recursive locking detected ]
4.2.0-rc8+ #61 Not tainted
---------------------------------------------
pulseaudio/980 is trying to acquire lock:
(&chip->shutdown_rwsem){.+.+.+}, at: [<ffffffffa0355dac>] snd_usb_autoresume+0x1d/0x52 [snd_usb_audio]
but task is already holding lock:
(&chip->shutdown_rwsem){.+.+.+}, at: [<ffffffffa0355dac>] snd_usb_autoresume+0x1d/0x52 [snd_usb_audio]
This comes from snd_usb_autoresume() invoking down_read() and it's
used in a nested way. Although it's basically safe, per se (as these
are read locks), it's better to reduce such spurious warnings.
The read lock is needed to guarantee the execution of "shutdown"
(cleanup at disconnection) task after all concurrent tasks are
finished. This can be implemented in another better way.
Also, the current check of chip->in_pm isn't good enough for
protecting the racy execution of multiple auto-resumes.
This patch rewrites the logic of snd_usb_autoresume() & co; namely,
- The recursive call of autopm is avoided by the new refcount,
chip->active. The chip->in_pm flag is removed accordingly.
- Instead of rwsem, another refcount, chip->usage_count, is introduced
for tracking the period to delay the shutdown procedure. At
the last clear of this refcount, wake_up() to the shutdown waiter is
called.
- The shutdown flag is replaced with shutdown atomic count; this is
for reducing the lock.
- Two new helpers are introduced to simplify the management of these
refcounts; snd_usb_lock_shutdown() increases the usage_count, checks
the shutdown state, and does autoresume. snd_usb_unlock_shutdown()
does the opposite. Most of mixer and other codes just need this,
and simply returns an error if it receives an error from lock.
Fixes: 9003ebb13f61 ('ALSA: usb-audio: Fix runtime PM unbalance')
Reported-and-tested-by: Alexnader Kuleshov <kuleshovmail@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-08-25 14:09:00 +00:00
|
|
|
snd_usb_unlock_shutdown(subs->stream->chip);
|
2018-07-31 12:28:45 +00:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2012-07-12 11:08:40 +00:00
|
|
|
}
|
|
|
|
|
2010-03-04 18:46:13 +00:00
|
|
|
subs->pcm_substream = NULL;
|
2011-03-11 13:51:12 +00:00
|
|
|
snd_usb_autosuspend(subs->stream->chip);
|
2012-04-12 11:51:12 +00:00
|
|
|
|
2012-07-12 11:08:40 +00:00
|
|
|
return 0;
|
2012-04-12 11:51:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Since a URB can handle only a single linear buffer, we must use double
|
|
|
|
* buffering when the data to be transferred overflows the buffer boundary.
|
|
|
|
* To avoid inconsistencies when updating hwptr_done, we use double buffering
|
|
|
|
* for all URBs.
|
|
|
|
*/
|
|
|
|
static void retire_capture_urb(struct snd_usb_substream *subs,
|
|
|
|
struct urb *urb)
|
|
|
|
{
|
|
|
|
struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
|
|
|
|
unsigned int stride, frames, bytes, oldptr;
|
|
|
|
int i, period_elapsed = 0;
|
|
|
|
unsigned long flags;
|
|
|
|
unsigned char *cp;
|
2012-12-19 17:39:05 +00:00
|
|
|
int current_frame_number;
|
|
|
|
|
|
|
|
/* read frame number here, update pointer in critical section */
|
|
|
|
current_frame_number = usb_get_current_frame_number(subs->dev);
|
2012-04-12 11:51:12 +00:00
|
|
|
|
|
|
|
stride = runtime->frame_bits >> 3;
|
|
|
|
|
|
|
|
for (i = 0; i < urb->number_of_packets; i++) {
|
2013-04-13 03:33:59 +00:00
|
|
|
cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset + subs->pkt_offset_adj;
|
2012-04-12 11:51:12 +00:00
|
|
|
if (urb->iso_frame_desc[i].status && printk_ratelimit()) {
|
2014-02-26 12:02:17 +00:00
|
|
|
dev_dbg(&subs->dev->dev, "frame %d active: %d\n",
|
|
|
|
i, urb->iso_frame_desc[i].status);
|
2012-04-12 11:51:12 +00:00
|
|
|
// continue;
|
|
|
|
}
|
|
|
|
bytes = urb->iso_frame_desc[i].actual_length;
|
2020-08-10 08:24:00 +00:00
|
|
|
if (subs->stream_offset_adj > 0) {
|
|
|
|
unsigned int adj = min(subs->stream_offset_adj, bytes);
|
|
|
|
cp += adj;
|
|
|
|
bytes -= adj;
|
|
|
|
subs->stream_offset_adj -= adj;
|
|
|
|
}
|
2012-04-12 11:51:12 +00:00
|
|
|
frames = bytes / stride;
|
|
|
|
if (!subs->txfr_quirk)
|
|
|
|
bytes = frames * stride;
|
|
|
|
if (bytes % (runtime->sample_bits >> 3) != 0) {
|
|
|
|
int oldbytes = bytes;
|
|
|
|
bytes = frames * stride;
|
2018-05-16 18:07:18 +00:00
|
|
|
dev_warn_ratelimited(&subs->dev->dev,
|
2014-02-26 12:02:17 +00:00
|
|
|
"Corrected urb data len. %d->%d\n",
|
2012-04-12 11:51:12 +00:00
|
|
|
oldbytes, bytes);
|
|
|
|
}
|
|
|
|
/* update the current pointer */
|
|
|
|
spin_lock_irqsave(&subs->lock, flags);
|
|
|
|
oldptr = subs->hwptr_done;
|
|
|
|
subs->hwptr_done += bytes;
|
2021-06-01 16:24:54 +00:00
|
|
|
if (subs->hwptr_done >= subs->buffer_bytes)
|
|
|
|
subs->hwptr_done -= subs->buffer_bytes;
|
2012-04-12 11:51:12 +00:00
|
|
|
frames = (bytes + (oldptr % stride)) / stride;
|
|
|
|
subs->transfer_done += frames;
|
|
|
|
if (subs->transfer_done >= runtime->period_size) {
|
|
|
|
subs->transfer_done -= runtime->period_size;
|
|
|
|
period_elapsed = 1;
|
|
|
|
}
|
2012-12-19 17:39:05 +00:00
|
|
|
|
|
|
|
/* realign last_frame_number */
|
|
|
|
subs->last_frame_number = current_frame_number;
|
|
|
|
|
2012-04-12 11:51:12 +00:00
|
|
|
spin_unlock_irqrestore(&subs->lock, flags);
|
|
|
|
/* copy a data chunk */
|
2021-06-01 16:24:54 +00:00
|
|
|
if (oldptr + bytes > subs->buffer_bytes) {
|
|
|
|
unsigned int bytes1 = subs->buffer_bytes - oldptr;
|
|
|
|
|
2012-04-12 11:51:12 +00:00
|
|
|
memcpy(runtime->dma_area + oldptr, cp, bytes1);
|
|
|
|
memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
|
|
|
|
} else {
|
|
|
|
memcpy(runtime->dma_area + oldptr, cp, bytes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (period_elapsed)
|
|
|
|
snd_pcm_period_elapsed(subs->pcm_substream);
|
|
|
|
}
|
|
|
|
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
static void urb_ctx_queue_advance(struct snd_usb_substream *subs,
|
|
|
|
struct urb *urb, unsigned int bytes)
|
|
|
|
{
|
|
|
|
struct snd_urb_ctx *ctx = urb->context;
|
|
|
|
|
|
|
|
ctx->queued += bytes;
|
|
|
|
subs->inflight_bytes += bytes;
|
|
|
|
subs->hwptr_done += bytes;
|
|
|
|
if (subs->hwptr_done >= subs->buffer_bytes)
|
|
|
|
subs->hwptr_done -= subs->buffer_bytes;
|
|
|
|
}
|
|
|
|
|
2013-04-16 16:01:38 +00:00
|
|
|
static inline void fill_playback_urb_dsd_dop(struct snd_usb_substream *subs,
|
|
|
|
struct urb *urb, unsigned int bytes)
|
|
|
|
{
|
|
|
|
struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
|
|
|
|
unsigned int dst_idx = 0;
|
|
|
|
unsigned int src_idx = subs->hwptr_done;
|
2021-06-01 16:24:54 +00:00
|
|
|
unsigned int wrap = subs->buffer_bytes;
|
2013-04-16 16:01:38 +00:00
|
|
|
u8 *dst = urb->transfer_buffer;
|
|
|
|
u8 *src = runtime->dma_area;
|
2022-08-09 18:15:44 +00:00
|
|
|
static const u8 marker[] = { 0x05, 0xfa };
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
unsigned int queued = 0;
|
2013-04-16 16:01:38 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The DSP DOP format defines a way to transport DSD samples over
|
|
|
|
* normal PCM data endpoints. It requires stuffing of marker bytes
|
|
|
|
* (0x05 and 0xfa, alternating per sample frame), and then expects
|
|
|
|
* 2 additional bytes of actual payload. The whole frame is stored
|
|
|
|
* LSB.
|
|
|
|
*
|
|
|
|
* Hence, for a stereo transport, the buffer layout looks like this,
|
|
|
|
* where L refers to left channel samples and R to right.
|
|
|
|
*
|
|
|
|
* L1 L2 0x05 R1 R2 0x05 L3 L4 0xfa R3 R4 0xfa
|
|
|
|
* L5 L6 0x05 R5 R6 0x05 L7 L8 0xfa R7 R8 0xfa
|
|
|
|
* .....
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
while (bytes--) {
|
|
|
|
if (++subs->dsd_dop.byte_idx == 3) {
|
|
|
|
/* frame boundary? */
|
|
|
|
dst[dst_idx++] = marker[subs->dsd_dop.marker];
|
|
|
|
src_idx += 2;
|
|
|
|
subs->dsd_dop.byte_idx = 0;
|
|
|
|
|
|
|
|
if (++subs->dsd_dop.channel % runtime->channels == 0) {
|
|
|
|
/* alternate the marker */
|
|
|
|
subs->dsd_dop.marker++;
|
|
|
|
subs->dsd_dop.marker %= ARRAY_SIZE(marker);
|
|
|
|
subs->dsd_dop.channel = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* stuff the DSD payload */
|
|
|
|
int idx = (src_idx + subs->dsd_dop.byte_idx - 1) % wrap;
|
2013-04-16 16:01:39 +00:00
|
|
|
|
|
|
|
if (subs->cur_audiofmt->dsd_bitrev)
|
|
|
|
dst[dst_idx++] = bitrev8(src[idx]);
|
|
|
|
else
|
|
|
|
dst[dst_idx++] = src[idx];
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
queued++;
|
2013-04-16 16:01:38 +00:00
|
|
|
}
|
|
|
|
}
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
|
|
|
|
urb_ctx_queue_advance(subs, urb, queued);
|
2013-04-16 16:01:38 +00:00
|
|
|
}
|
|
|
|
|
2021-06-01 16:24:56 +00:00
|
|
|
/* copy bit-reversed bytes onto transfer buffer */
|
|
|
|
static void fill_playback_urb_dsd_bitrev(struct snd_usb_substream *subs,
|
|
|
|
struct urb *urb, unsigned int bytes)
|
|
|
|
{
|
|
|
|
struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
|
|
|
|
const u8 *src = runtime->dma_area;
|
|
|
|
u8 *buf = urb->transfer_buffer;
|
|
|
|
int i, ofs = subs->hwptr_done;
|
|
|
|
|
|
|
|
for (i = 0; i < bytes; i++) {
|
|
|
|
*buf++ = bitrev8(src[ofs]);
|
|
|
|
if (++ofs >= subs->buffer_bytes)
|
|
|
|
ofs = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
urb_ctx_queue_advance(subs, urb, bytes);
|
|
|
|
}
|
|
|
|
|
2015-10-19 06:52:52 +00:00
|
|
|
static void copy_to_urb(struct snd_usb_substream *subs, struct urb *urb,
|
|
|
|
int offset, int stride, unsigned int bytes)
|
2015-10-19 06:52:49 +00:00
|
|
|
{
|
|
|
|
struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
|
|
|
|
|
2021-06-01 16:24:54 +00:00
|
|
|
if (subs->hwptr_done + bytes > subs->buffer_bytes) {
|
2015-10-19 06:52:49 +00:00
|
|
|
/* err, the transferred area goes over buffer boundary. */
|
2021-06-01 16:24:54 +00:00
|
|
|
unsigned int bytes1 = subs->buffer_bytes - subs->hwptr_done;
|
|
|
|
|
2015-10-19 06:52:52 +00:00
|
|
|
memcpy(urb->transfer_buffer + offset,
|
2015-10-19 06:52:49 +00:00
|
|
|
runtime->dma_area + subs->hwptr_done, bytes1);
|
2015-10-19 06:52:52 +00:00
|
|
|
memcpy(urb->transfer_buffer + offset + bytes1,
|
2015-10-19 06:52:49 +00:00
|
|
|
runtime->dma_area, bytes - bytes1);
|
|
|
|
} else {
|
2015-10-19 06:52:52 +00:00
|
|
|
memcpy(urb->transfer_buffer + offset,
|
2015-10-19 06:52:49 +00:00
|
|
|
runtime->dma_area + subs->hwptr_done, bytes);
|
|
|
|
}
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
|
|
|
|
urb_ctx_queue_advance(subs, urb, bytes);
|
2015-10-19 06:52:49 +00:00
|
|
|
}
|
|
|
|
|
ALSA: USB-audio: Add quirk for Zoom R16/24 playback
The Zoom R16/24 have a nonstandard playback format where each isochronous
packet contains a length descriptor in the first four bytes. (Curiously,
capture data does not contain this and requires no quirk.)
The quirk involves adding the extra length descriptor whenever outgoing
isochronous packets are generated, both in pcm.c (outgoing audio) and
endpoint.c (silent data).
In order to make the quirk as unintrusive as possible, for
pcm.c:prepare_playback_urb(), the isochronous packet descriptors are
initially set up in the same way no matter if the quirk is enabled or not.
Once it is time to actually copy the data into the outgoing packet buffer
(together with the added length descriptors) the isochronous descriptors
are adjusted in order take the increased payload length into account.
For endpoint.c:prepare_silent_urb() it makes more sense to modify the
actual function, partly because the function is less complex to start with
and partly because it is not as time-critical as prepare_playback_urb()
(whose bulk is run with interrupts disabled), so the (minute) additional
time spent in the non-quirk case is motivated by the simplicity of having
a single function for all cases.
The quirk is controlled by the new tx_length_quirk member in struct
snd_usb_substream and struct snd_usb_audio, which is conveyed to pcm.c
and endpoint.c from quirks.c in a similar manner to the txfr_quirk member
in the same structs.
In contrast to txfr_quirk however, the quirk is enabled directly in
quirks.c:create_standard_audio_quirk() by checking the USB ID in that
function. Another option would be to introduce a new
QUIRK_AUDIO_ZOOM_INTERFACE or somesuch, which would have made the quirk
very plain to see in the quirk table, but it was felt that the additional
code needed to implement it this way would just make the implementation
more complex with no real gain.
Tested with a Zoom R16, both by doing capture and playback separately
using arecord and aplay (8 channel capture and 2 channel playback,
respectively), as well as capture and playback together using Ardour, as
well as Audacity and Qtractor together with jackd.
The R24 is reportedly compatible with the R16 when used as an audio
interface. Both devices share the same USB ID and have the same number of
inputs (8) and outputs (2). Therefore "R16/24" is mentioned throughout the
patch.
Regression tested using an Edirol UA-5 in both class compliant (16-bit)
and "advanced" (24 bit, forces the use of quirks) modes.
Signed-off-by: Ricard Wanderlof <ricardw@axis.com>
Tested-by: Panu Matilainen <pmatilai@laiskiainen.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-10-19 06:52:53 +00:00
|
|
|
static unsigned int copy_to_urb_quirk(struct snd_usb_substream *subs,
|
|
|
|
struct urb *urb, int stride,
|
|
|
|
unsigned int bytes)
|
|
|
|
{
|
|
|
|
__le32 packet_length;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Put __le32 length descriptor at start of each packet. */
|
|
|
|
for (i = 0; i < urb->number_of_packets; i++) {
|
|
|
|
unsigned int length = urb->iso_frame_desc[i].length;
|
|
|
|
unsigned int offset = urb->iso_frame_desc[i].offset;
|
|
|
|
|
|
|
|
packet_length = cpu_to_le32(length);
|
|
|
|
offset += i * sizeof(packet_length);
|
|
|
|
urb->iso_frame_desc[i].offset = offset;
|
|
|
|
urb->iso_frame_desc[i].length += sizeof(packet_length);
|
|
|
|
memcpy(urb->transfer_buffer + offset,
|
|
|
|
&packet_length, sizeof(packet_length));
|
|
|
|
copy_to_urb(subs, urb, offset + sizeof(packet_length),
|
|
|
|
stride, length);
|
|
|
|
}
|
|
|
|
/* Adjust transfer size accordingly. */
|
|
|
|
bytes += urb->number_of_packets * sizeof(packet_length);
|
|
|
|
return bytes;
|
|
|
|
}
|
|
|
|
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
static int prepare_playback_urb(struct snd_usb_substream *subs,
|
|
|
|
struct urb *urb,
|
|
|
|
bool in_stream_lock)
|
2012-04-12 11:51:12 +00:00
|
|
|
{
|
|
|
|
struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
|
2012-08-30 16:52:30 +00:00
|
|
|
struct snd_usb_endpoint *ep = subs->data_endpoint;
|
2012-04-12 11:51:12 +00:00
|
|
|
struct snd_urb_ctx *ctx = urb->context;
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
unsigned int frames, bytes;
|
|
|
|
int counts;
|
|
|
|
unsigned int transfer_done, frame_limit, avail = 0;
|
2012-04-12 11:51:12 +00:00
|
|
|
int i, stride, period_elapsed = 0;
|
|
|
|
unsigned long flags;
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
int err = 0;
|
2012-04-12 11:51:12 +00:00
|
|
|
|
2021-06-01 16:24:54 +00:00
|
|
|
stride = ep->stride;
|
2012-04-12 11:51:12 +00:00
|
|
|
|
|
|
|
frames = 0;
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
ctx->queued = 0;
|
2012-04-12 11:51:12 +00:00
|
|
|
urb->number_of_packets = 0;
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
|
2012-04-12 11:51:12 +00:00
|
|
|
spin_lock_irqsave(&subs->lock, flags);
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
frame_limit = subs->frame_limit + ep->max_urb_frames;
|
|
|
|
transfer_done = subs->transfer_done;
|
|
|
|
|
|
|
|
if (subs->lowlatency_playback &&
|
2022-09-26 13:55:54 +00:00
|
|
|
runtime->state != SNDRV_PCM_STATE_DRAINING) {
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
unsigned int hwptr = subs->hwptr_done / stride;
|
|
|
|
|
|
|
|
/* calculate the byte offset-in-buffer of the appl_ptr */
|
|
|
|
avail = (runtime->control->appl_ptr - runtime->hw_ptr_base)
|
|
|
|
% runtime->buffer_size;
|
|
|
|
if (avail <= hwptr)
|
|
|
|
avail += runtime->buffer_size;
|
|
|
|
avail -= hwptr;
|
|
|
|
}
|
|
|
|
|
2012-04-12 11:51:12 +00:00
|
|
|
for (i = 0; i < ctx->packets; i++) {
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, avail);
|
|
|
|
if (counts < 0)
|
|
|
|
break;
|
2012-04-12 11:51:12 +00:00
|
|
|
/* set up descriptor */
|
2021-06-01 16:24:54 +00:00
|
|
|
urb->iso_frame_desc[i].offset = frames * stride;
|
|
|
|
urb->iso_frame_desc[i].length = counts * stride;
|
2012-04-12 11:51:12 +00:00
|
|
|
frames += counts;
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
avail -= counts;
|
2012-04-12 11:51:12 +00:00
|
|
|
urb->number_of_packets++;
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
transfer_done += counts;
|
|
|
|
if (transfer_done >= runtime->period_size) {
|
|
|
|
transfer_done -= runtime->period_size;
|
|
|
|
frame_limit = 0;
|
2012-04-12 11:51:12 +00:00
|
|
|
period_elapsed = 1;
|
|
|
|
if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
if (transfer_done > 0) {
|
2012-04-12 11:51:12 +00:00
|
|
|
/* FIXME: fill-max mode is not
|
|
|
|
* supported yet */
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
frames -= transfer_done;
|
|
|
|
counts -= transfer_done;
|
2012-04-12 11:51:12 +00:00
|
|
|
urb->iso_frame_desc[i].length =
|
2021-06-01 16:24:54 +00:00
|
|
|
counts * stride;
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
transfer_done = 0;
|
2012-04-12 11:51:12 +00:00
|
|
|
}
|
|
|
|
i++;
|
|
|
|
if (i < ctx->packets) {
|
|
|
|
/* add a transfer delimiter */
|
|
|
|
urb->iso_frame_desc[i].offset =
|
2021-06-01 16:24:54 +00:00
|
|
|
frames * stride;
|
2012-04-12 11:51:12 +00:00
|
|
|
urb->iso_frame_desc[i].length = 0;
|
|
|
|
urb->number_of_packets++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
ALSA: improve buffer size computations for USB PCM audio
This patch changes the way URBs are allocated and their sizes are
determined for PCM playback in the snd-usb-audio driver. Currently
the driver allocates too few URBs for endpoints that don't use
implicit sync, making underruns more likely to occur. This may be a
holdover from before I/O delays could be measured accurately; in any
case, it is no longer necessary.
The patch allocates as many URBs as possible, subject to four
limitations:
The total number of URBs for the endpoint is not allowed to
exceed MAX_URBS (which the patch increases from 8 to 12).
The total number of packets per URB is not allowed to exceed
MAX_PACKS (or MAX_PACKS_HS for high-speed devices), which is
decreased from 20 to 6.
The total duration of queued data is not allowed to exceed
MAX_QUEUE, which is decreased from 24 ms to 18 ms.
The total number of ALSA frames in the output queue is not
allowed to exceed the ALSA buffer size.
The last requirement is the hardest to implement. Currently the
number of URBs needed to fill a buffer cannot be determined in
advance, because a buffer contains a fixed number of frames whereas
the number of frames in an URB varies to match shifts in the device's
clock rate. To solve this problem, the patch changes the logic for
deciding how many packets an URB should contain. Rather than using as
many as possible without exceeding an ALSA period boundary, now the
driver uses only as many packets as needed to transfer a predetermined
number of frames. As a result, unless the device's clock has an
exceedingly variable rate, the number of URBs making up each period
(and hence each buffer) will remain constant.
The overall effect of the patch is that playback works better in
low-latency settings. The user can still specify values for
frames/period and periods/buffer that exceed the capabilities of the
hardware, of course. But for values that are within those
capabilities, the performance will be improved. For example, testing
shows that a high-speed device can handle 32 frames/period and 3
periods/buffer at 48 KHz, whereas the current driver starts to get
glitchy at 64 frames/period and 2 periods/buffer.
A side effect of these changes is that the "nrpacks" module parameter
is no longer used. The patch removes it.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: Clemens Ladisch <clemens@ladisch.de>
Tested-by: Daniel Mack <zonque@gmail.com>
Tested-by: Eldad Zack <eldad@fogrefinery.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-09-24 19:51:58 +00:00
|
|
|
/* finish at the period boundary or after enough frames */
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
if ((period_elapsed || transfer_done >= frame_limit) &&
|
ALSA: improve buffer size computations for USB PCM audio
This patch changes the way URBs are allocated and their sizes are
determined for PCM playback in the snd-usb-audio driver. Currently
the driver allocates too few URBs for endpoints that don't use
implicit sync, making underruns more likely to occur. This may be a
holdover from before I/O delays could be measured accurately; in any
case, it is no longer necessary.
The patch allocates as many URBs as possible, subject to four
limitations:
The total number of URBs for the endpoint is not allowed to
exceed MAX_URBS (which the patch increases from 8 to 12).
The total number of packets per URB is not allowed to exceed
MAX_PACKS (or MAX_PACKS_HS for high-speed devices), which is
decreased from 20 to 6.
The total duration of queued data is not allowed to exceed
MAX_QUEUE, which is decreased from 24 ms to 18 ms.
The total number of ALSA frames in the output queue is not
allowed to exceed the ALSA buffer size.
The last requirement is the hardest to implement. Currently the
number of URBs needed to fill a buffer cannot be determined in
advance, because a buffer contains a fixed number of frames whereas
the number of frames in an URB varies to match shifts in the device's
clock rate. To solve this problem, the patch changes the logic for
deciding how many packets an URB should contain. Rather than using as
many as possible without exceeding an ALSA period boundary, now the
driver uses only as many packets as needed to transfer a predetermined
number of frames. As a result, unless the device's clock has an
exceedingly variable rate, the number of URBs making up each period
(and hence each buffer) will remain constant.
The overall effect of the patch is that playback works better in
low-latency settings. The user can still specify values for
frames/period and periods/buffer that exceed the capabilities of the
hardware, of course. But for values that are within those
capabilities, the performance will be improved. For example, testing
shows that a high-speed device can handle 32 frames/period and 3
periods/buffer at 48 KHz, whereas the current driver starts to get
glitchy at 64 frames/period and 2 periods/buffer.
A side effect of these changes is that the "nrpacks" module parameter
is no longer used. The patch removes it.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: Clemens Ladisch <clemens@ladisch.de>
Tested-by: Daniel Mack <zonque@gmail.com>
Tested-by: Eldad Zack <eldad@fogrefinery.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2013-09-24 19:51:58 +00:00
|
|
|
!snd_usb_endpoint_implicit_feedback_sink(ep))
|
2012-04-12 11:51:12 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-04-16 16:01:38 +00:00
|
|
|
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
if (!frames) {
|
|
|
|
err = -EAGAIN;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytes = frames * stride;
|
|
|
|
subs->transfer_done = transfer_done;
|
|
|
|
subs->frame_limit = frame_limit;
|
2020-11-23 08:53:36 +00:00
|
|
|
if (unlikely(ep->cur_format == SNDRV_PCM_FORMAT_DSD_U16_LE &&
|
2013-04-16 16:01:38 +00:00
|
|
|
subs->cur_audiofmt->dsd_dop)) {
|
|
|
|
fill_playback_urb_dsd_dop(subs, urb, bytes);
|
2020-11-23 08:53:36 +00:00
|
|
|
} else if (unlikely(ep->cur_format == SNDRV_PCM_FORMAT_DSD_U8 &&
|
2013-04-16 16:01:39 +00:00
|
|
|
subs->cur_audiofmt->dsd_bitrev)) {
|
2021-06-01 16:24:56 +00:00
|
|
|
fill_playback_urb_dsd_bitrev(subs, urb, bytes);
|
2012-04-12 11:51:12 +00:00
|
|
|
} else {
|
2013-04-16 16:01:38 +00:00
|
|
|
/* usual PCM */
|
ALSA: USB-audio: Add quirk for Zoom R16/24 playback
The Zoom R16/24 have a nonstandard playback format where each isochronous
packet contains a length descriptor in the first four bytes. (Curiously,
capture data does not contain this and requires no quirk.)
The quirk involves adding the extra length descriptor whenever outgoing
isochronous packets are generated, both in pcm.c (outgoing audio) and
endpoint.c (silent data).
In order to make the quirk as unintrusive as possible, for
pcm.c:prepare_playback_urb(), the isochronous packet descriptors are
initially set up in the same way no matter if the quirk is enabled or not.
Once it is time to actually copy the data into the outgoing packet buffer
(together with the added length descriptors) the isochronous descriptors
are adjusted in order take the increased payload length into account.
For endpoint.c:prepare_silent_urb() it makes more sense to modify the
actual function, partly because the function is less complex to start with
and partly because it is not as time-critical as prepare_playback_urb()
(whose bulk is run with interrupts disabled), so the (minute) additional
time spent in the non-quirk case is motivated by the simplicity of having
a single function for all cases.
The quirk is controlled by the new tx_length_quirk member in struct
snd_usb_substream and struct snd_usb_audio, which is conveyed to pcm.c
and endpoint.c from quirks.c in a similar manner to the txfr_quirk member
in the same structs.
In contrast to txfr_quirk however, the quirk is enabled directly in
quirks.c:create_standard_audio_quirk() by checking the USB ID in that
function. Another option would be to introduce a new
QUIRK_AUDIO_ZOOM_INTERFACE or somesuch, which would have made the quirk
very plain to see in the quirk table, but it was felt that the additional
code needed to implement it this way would just make the implementation
more complex with no real gain.
Tested with a Zoom R16, both by doing capture and playback separately
using arecord and aplay (8 channel capture and 2 channel playback,
respectively), as well as capture and playback together using Ardour, as
well as Audacity and Qtractor together with jackd.
The R24 is reportedly compatible with the R16 when used as an audio
interface. Both devices share the same USB ID and have the same number of
inputs (8) and outputs (2). Therefore "R16/24" is mentioned throughout the
patch.
Regression tested using an Edirol UA-5 in both class compliant (16-bit)
and "advanced" (24 bit, forces the use of quirks) modes.
Signed-off-by: Ricard Wanderlof <ricardw@axis.com>
Tested-by: Panu Matilainen <pmatilai@laiskiainen.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2015-10-19 06:52:53 +00:00
|
|
|
if (!subs->tx_length_quirk)
|
|
|
|
copy_to_urb(subs, urb, 0, stride, bytes);
|
|
|
|
else
|
|
|
|
bytes = copy_to_urb_quirk(subs, urb, stride, bytes);
|
|
|
|
/* bytes is now amount of outgoing data */
|
2012-04-12 11:51:12 +00:00
|
|
|
}
|
2013-04-16 16:01:38 +00:00
|
|
|
|
2012-08-30 16:52:29 +00:00
|
|
|
subs->last_frame_number = usb_get_current_frame_number(subs->dev);
|
|
|
|
|
2015-02-06 21:55:53 +00:00
|
|
|
if (subs->trigger_tstamp_pending_update) {
|
|
|
|
/* this is the first actual URB submitted,
|
|
|
|
* update trigger timestamp to reflect actual start time
|
|
|
|
*/
|
|
|
|
snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
|
|
|
|
subs->trigger_tstamp_pending_update = false;
|
|
|
|
}
|
|
|
|
|
2021-09-29 08:08:38 +00:00
|
|
|
if (period_elapsed && !subs->running && subs->lowlatency_playback) {
|
ALSA: usb-audio: Reduce latency at playback start, take#2
This is another attempt for the reduction of the latency at the start
of a USB audio playback stream. The first attempt in the commit
9ce650a75a3b caused an unexpected regression (a deadlock with pipewire
usage) and was later reverted by the commit 4b820e167bf6. The devils
are always living in details, of course; the cause of the deadlock was
the call of snd_pcm_period_elapsed() inside prepare_playback_urb()
callback. In the original code, this callback is never called from
the stream lock context as it's driven solely from the URB complete
callback. Along with the movement of the URB submission into the
trigger START, this prepare call may be also executed in the stream
lock context, hence it deadlocked with the another lock in
snd_pcm_period_elapsed(). (Note that this happens only conditionally
with a small period size that matches with the URB buffer length,
which was a reason I overlooked during my tests. Also, the problem
wasn't seen in the capture stream because the capture stream handles
the period-elapsed only at retire callback that isn't executed at the
trigger.)
If it were only about avoiding the deadlock, it'd be possible to use
snd_pcm_period_elapsed_under_stream_lock() as a solution. However, in
general, the period elapsed notification must be sent after the actual
stream start, and replacing the call wouldn't satisfy the pattern.
A better option is to delay the notification after the stream start
procedure finished, instead. In the case of USB framework, one of the
fitting place would be the complete callback of the first URB.
So, as a workaround of the deadlock and the order fixes above, in
addition to the re-applying the changes in the commit 9ce650a75a3,
this patch introduces a new flag indicating the delayed period-elapsed
handling and sets it under the possible deadlock condition
(i.e. prepare callback being called before subs->running is set).
Once when the flag is set, the period-elapsed call is handled at a
later URB complete call instead.
As a reference for the original motivation for the low-latency change,
I cite here again:
| USB-audio driver behaves a bit strangely for the playback stream --
| namely, it starts sending silent packets at PCM prepare state while
| the actual data is submitted at first when the trigger START is
| kicked off. This is a workaround for the behavior where URBs are
| processed too quickly at the beginning. That is, if we start
| submitting URBs at trigger START, the first few URBs will be
| immediately completed, and this would result in the immediate
| period-elapsed calls right after the start, which may confuse
| applications.
|
| OTOH, submitting the data after silent URBs would, of course, result
| in a certain delay of the actual data processing, and this is rather
| more serious problem on modern systems, in practice.
|
| This patch tries to revert the workaround and lets the URB
| submission starting at PCM trigger for the playback again. As far
| as I've tested with various backends (native ALSA, PA, JACK, PW), I
| haven't seen any problems (famous last words :)
|
| Note that the capture stream handling needs no such workaround,
| since the capture is driven per received URB.
Link: https://lore.kernel.org/r/4e71531f-4535-fd46-040e-506a3c256bbd@marcan.st
Link: https://lore.kernel.org/r/s5hbl7li0fe.wl-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/20210707112447.27485-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-07-07 11:24:47 +00:00
|
|
|
subs->period_elapsed_pending = 1;
|
|
|
|
period_elapsed = 0;
|
|
|
|
}
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
|
|
|
|
unlock:
|
2012-04-12 11:51:12 +00:00
|
|
|
spin_unlock_irqrestore(&subs->lock, flags);
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2012-04-12 11:51:12 +00:00
|
|
|
urb->transfer_buffer_length = bytes;
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
if (period_elapsed) {
|
|
|
|
if (in_stream_lock)
|
|
|
|
snd_pcm_period_elapsed_under_stream_lock(subs->pcm_substream);
|
|
|
|
else
|
|
|
|
snd_pcm_period_elapsed(subs->pcm_substream);
|
|
|
|
}
|
|
|
|
return 0;
|
2012-04-12 11:51:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* process after playback data complete
|
|
|
|
* - decrease the delay count again
|
|
|
|
*/
|
|
|
|
static void retire_playback_urb(struct snd_usb_substream *subs,
|
|
|
|
struct urb *urb)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
struct snd_urb_ctx *ctx = urb->context;
|
ALSA: usb-audio: Reduce latency at playback start, take#2
This is another attempt for the reduction of the latency at the start
of a USB audio playback stream. The first attempt in the commit
9ce650a75a3b caused an unexpected regression (a deadlock with pipewire
usage) and was later reverted by the commit 4b820e167bf6. The devils
are always living in details, of course; the cause of the deadlock was
the call of snd_pcm_period_elapsed() inside prepare_playback_urb()
callback. In the original code, this callback is never called from
the stream lock context as it's driven solely from the URB complete
callback. Along with the movement of the URB submission into the
trigger START, this prepare call may be also executed in the stream
lock context, hence it deadlocked with the another lock in
snd_pcm_period_elapsed(). (Note that this happens only conditionally
with a small period size that matches with the URB buffer length,
which was a reason I overlooked during my tests. Also, the problem
wasn't seen in the capture stream because the capture stream handles
the period-elapsed only at retire callback that isn't executed at the
trigger.)
If it were only about avoiding the deadlock, it'd be possible to use
snd_pcm_period_elapsed_under_stream_lock() as a solution. However, in
general, the period elapsed notification must be sent after the actual
stream start, and replacing the call wouldn't satisfy the pattern.
A better option is to delay the notification after the stream start
procedure finished, instead. In the case of USB framework, one of the
fitting place would be the complete callback of the first URB.
So, as a workaround of the deadlock and the order fixes above, in
addition to the re-applying the changes in the commit 9ce650a75a3,
this patch introduces a new flag indicating the delayed period-elapsed
handling and sets it under the possible deadlock condition
(i.e. prepare callback being called before subs->running is set).
Once when the flag is set, the period-elapsed call is handled at a
later URB complete call instead.
As a reference for the original motivation for the low-latency change,
I cite here again:
| USB-audio driver behaves a bit strangely for the playback stream --
| namely, it starts sending silent packets at PCM prepare state while
| the actual data is submitted at first when the trigger START is
| kicked off. This is a workaround for the behavior where URBs are
| processed too quickly at the beginning. That is, if we start
| submitting URBs at trigger START, the first few URBs will be
| immediately completed, and this would result in the immediate
| period-elapsed calls right after the start, which may confuse
| applications.
|
| OTOH, submitting the data after silent URBs would, of course, result
| in a certain delay of the actual data processing, and this is rather
| more serious problem on modern systems, in practice.
|
| This patch tries to revert the workaround and lets the URB
| submission starting at PCM trigger for the playback again. As far
| as I've tested with various backends (native ALSA, PA, JACK, PW), I
| haven't seen any problems (famous last words :)
|
| Note that the capture stream handling needs no such workaround,
| since the capture is driven per received URB.
Link: https://lore.kernel.org/r/4e71531f-4535-fd46-040e-506a3c256bbd@marcan.st
Link: https://lore.kernel.org/r/s5hbl7li0fe.wl-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/20210707112447.27485-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-07-07 11:24:47 +00:00
|
|
|
bool period_elapsed = false;
|
2012-09-06 12:58:00 +00:00
|
|
|
|
2012-04-12 11:51:12 +00:00
|
|
|
spin_lock_irqsave(&subs->lock, flags);
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
if (ctx->queued) {
|
|
|
|
if (subs->inflight_bytes >= ctx->queued)
|
|
|
|
subs->inflight_bytes -= ctx->queued;
|
|
|
|
else
|
|
|
|
subs->inflight_bytes = 0;
|
2012-11-23 15:00:37 +00:00
|
|
|
}
|
|
|
|
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
subs->last_frame_number = usb_get_current_frame_number(subs->dev);
|
ALSA: usb-audio: Reduce latency at playback start, take#2
This is another attempt for the reduction of the latency at the start
of a USB audio playback stream. The first attempt in the commit
9ce650a75a3b caused an unexpected regression (a deadlock with pipewire
usage) and was later reverted by the commit 4b820e167bf6. The devils
are always living in details, of course; the cause of the deadlock was
the call of snd_pcm_period_elapsed() inside prepare_playback_urb()
callback. In the original code, this callback is never called from
the stream lock context as it's driven solely from the URB complete
callback. Along with the movement of the URB submission into the
trigger START, this prepare call may be also executed in the stream
lock context, hence it deadlocked with the another lock in
snd_pcm_period_elapsed(). (Note that this happens only conditionally
with a small period size that matches with the URB buffer length,
which was a reason I overlooked during my tests. Also, the problem
wasn't seen in the capture stream because the capture stream handles
the period-elapsed only at retire callback that isn't executed at the
trigger.)
If it were only about avoiding the deadlock, it'd be possible to use
snd_pcm_period_elapsed_under_stream_lock() as a solution. However, in
general, the period elapsed notification must be sent after the actual
stream start, and replacing the call wouldn't satisfy the pattern.
A better option is to delay the notification after the stream start
procedure finished, instead. In the case of USB framework, one of the
fitting place would be the complete callback of the first URB.
So, as a workaround of the deadlock and the order fixes above, in
addition to the re-applying the changes in the commit 9ce650a75a3,
this patch introduces a new flag indicating the delayed period-elapsed
handling and sets it under the possible deadlock condition
(i.e. prepare callback being called before subs->running is set).
Once when the flag is set, the period-elapsed call is handled at a
later URB complete call instead.
As a reference for the original motivation for the low-latency change,
I cite here again:
| USB-audio driver behaves a bit strangely for the playback stream --
| namely, it starts sending silent packets at PCM prepare state while
| the actual data is submitted at first when the trigger START is
| kicked off. This is a workaround for the behavior where URBs are
| processed too quickly at the beginning. That is, if we start
| submitting URBs at trigger START, the first few URBs will be
| immediately completed, and this would result in the immediate
| period-elapsed calls right after the start, which may confuse
| applications.
|
| OTOH, submitting the data after silent URBs would, of course, result
| in a certain delay of the actual data processing, and this is rather
| more serious problem on modern systems, in practice.
|
| This patch tries to revert the workaround and lets the URB
| submission starting at PCM trigger for the playback again. As far
| as I've tested with various backends (native ALSA, PA, JACK, PW), I
| haven't seen any problems (famous last words :)
|
| Note that the capture stream handling needs no such workaround,
| since the capture is driven per received URB.
Link: https://lore.kernel.org/r/4e71531f-4535-fd46-040e-506a3c256bbd@marcan.st
Link: https://lore.kernel.org/r/s5hbl7li0fe.wl-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/20210707112447.27485-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-07-07 11:24:47 +00:00
|
|
|
if (subs->running) {
|
|
|
|
period_elapsed = subs->period_elapsed_pending;
|
|
|
|
subs->period_elapsed_pending = 0;
|
|
|
|
}
|
2012-04-12 11:51:12 +00:00
|
|
|
spin_unlock_irqrestore(&subs->lock, flags);
|
ALSA: usb-audio: Reduce latency at playback start, take#2
This is another attempt for the reduction of the latency at the start
of a USB audio playback stream. The first attempt in the commit
9ce650a75a3b caused an unexpected regression (a deadlock with pipewire
usage) and was later reverted by the commit 4b820e167bf6. The devils
are always living in details, of course; the cause of the deadlock was
the call of snd_pcm_period_elapsed() inside prepare_playback_urb()
callback. In the original code, this callback is never called from
the stream lock context as it's driven solely from the URB complete
callback. Along with the movement of the URB submission into the
trigger START, this prepare call may be also executed in the stream
lock context, hence it deadlocked with the another lock in
snd_pcm_period_elapsed(). (Note that this happens only conditionally
with a small period size that matches with the URB buffer length,
which was a reason I overlooked during my tests. Also, the problem
wasn't seen in the capture stream because the capture stream handles
the period-elapsed only at retire callback that isn't executed at the
trigger.)
If it were only about avoiding the deadlock, it'd be possible to use
snd_pcm_period_elapsed_under_stream_lock() as a solution. However, in
general, the period elapsed notification must be sent after the actual
stream start, and replacing the call wouldn't satisfy the pattern.
A better option is to delay the notification after the stream start
procedure finished, instead. In the case of USB framework, one of the
fitting place would be the complete callback of the first URB.
So, as a workaround of the deadlock and the order fixes above, in
addition to the re-applying the changes in the commit 9ce650a75a3,
this patch introduces a new flag indicating the delayed period-elapsed
handling and sets it under the possible deadlock condition
(i.e. prepare callback being called before subs->running is set).
Once when the flag is set, the period-elapsed call is handled at a
later URB complete call instead.
As a reference for the original motivation for the low-latency change,
I cite here again:
| USB-audio driver behaves a bit strangely for the playback stream --
| namely, it starts sending silent packets at PCM prepare state while
| the actual data is submitted at first when the trigger START is
| kicked off. This is a workaround for the behavior where URBs are
| processed too quickly at the beginning. That is, if we start
| submitting URBs at trigger START, the first few URBs will be
| immediately completed, and this would result in the immediate
| period-elapsed calls right after the start, which may confuse
| applications.
|
| OTOH, submitting the data after silent URBs would, of course, result
| in a certain delay of the actual data processing, and this is rather
| more serious problem on modern systems, in practice.
|
| This patch tries to revert the workaround and lets the URB
| submission starting at PCM trigger for the playback again. As far
| as I've tested with various backends (native ALSA, PA, JACK, PW), I
| haven't seen any problems (famous last words :)
|
| Note that the capture stream handling needs no such workaround,
| since the capture is driven per received URB.
Link: https://lore.kernel.org/r/4e71531f-4535-fd46-040e-506a3c256bbd@marcan.st
Link: https://lore.kernel.org/r/s5hbl7li0fe.wl-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/20210707112447.27485-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-07-07 11:24:47 +00:00
|
|
|
if (period_elapsed)
|
|
|
|
snd_pcm_period_elapsed(subs->pcm_substream);
|
2010-03-04 18:46:13 +00:00
|
|
|
}
|
|
|
|
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
/* PCM ack callback for the playback stream;
|
|
|
|
* this plays a role only when the stream is running in low-latency mode.
|
|
|
|
*/
|
|
|
|
static int snd_usb_pcm_playback_ack(struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct snd_usb_substream *subs = substream->runtime->private_data;
|
|
|
|
struct snd_usb_endpoint *ep;
|
|
|
|
|
|
|
|
if (!subs->lowlatency_playback || !subs->running)
|
|
|
|
return 0;
|
|
|
|
ep = subs->data_endpoint;
|
|
|
|
if (!ep)
|
|
|
|
return 0;
|
|
|
|
/* When no more in-flight URBs available, try to process the pending
|
|
|
|
* outputs here
|
|
|
|
*/
|
|
|
|
if (!ep->active_mask)
|
ALSA: usb-audio: Fix recursive locking at XRUN during syncing
The recent support of low latency playback in USB-audio driver made
the snd_usb_queue_pending_output_urbs() function to be called via PCM
ack ops. In the new code path, the function is performed already in
the PCM stream lock. The problem is that, when an XRUN is detected,
the function calls snd_pcm_xrun() to notify, but snd_pcm_xrun() is
supposed to be called only outside the stream lock. As a result, it
leads to a deadlock of PCM stream locking.
For avoiding such a recursive locking, this patch adds an additional
check to the code paths in PCM core that call the ack callback; now it
checks the error code from the callback, and if it's -EPIPE, the XRUN
is handled in the PCM core side gracefully. Along with it, the
USB-audio driver code is changed to follow that, i.e. -EPIPE is
returned instead of the explicit snd_pcm_xrun() call when the function
is performed already in the stream lock.
Fixes: d5f871f89e21 ("ALSA: usb-audio: Improved lowlatency playback support")
Reported-and-tested-by: John Keeping <john@metanate.com>
Link: https://lore.kernel.org/r/20230317195128.3911155-1-john@metanate.com
Reviewed-by: Jaroslav Kysela <perex@perex.cz>
Reviewed-by; Takashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/20230320142838.494-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2023-03-20 14:28:38 +00:00
|
|
|
return snd_usb_queue_pending_output_urbs(ep, true);
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-04-12 11:51:12 +00:00
|
|
|
static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream,
|
|
|
|
int cmd)
|
|
|
|
{
|
|
|
|
struct snd_usb_substream *subs = substream->runtime->private_data;
|
ALSA: usb-audio: Reduce latency at playback start, take#2
This is another attempt for the reduction of the latency at the start
of a USB audio playback stream. The first attempt in the commit
9ce650a75a3b caused an unexpected regression (a deadlock with pipewire
usage) and was later reverted by the commit 4b820e167bf6. The devils
are always living in details, of course; the cause of the deadlock was
the call of snd_pcm_period_elapsed() inside prepare_playback_urb()
callback. In the original code, this callback is never called from
the stream lock context as it's driven solely from the URB complete
callback. Along with the movement of the URB submission into the
trigger START, this prepare call may be also executed in the stream
lock context, hence it deadlocked with the another lock in
snd_pcm_period_elapsed(). (Note that this happens only conditionally
with a small period size that matches with the URB buffer length,
which was a reason I overlooked during my tests. Also, the problem
wasn't seen in the capture stream because the capture stream handles
the period-elapsed only at retire callback that isn't executed at the
trigger.)
If it were only about avoiding the deadlock, it'd be possible to use
snd_pcm_period_elapsed_under_stream_lock() as a solution. However, in
general, the period elapsed notification must be sent after the actual
stream start, and replacing the call wouldn't satisfy the pattern.
A better option is to delay the notification after the stream start
procedure finished, instead. In the case of USB framework, one of the
fitting place would be the complete callback of the first URB.
So, as a workaround of the deadlock and the order fixes above, in
addition to the re-applying the changes in the commit 9ce650a75a3,
this patch introduces a new flag indicating the delayed period-elapsed
handling and sets it under the possible deadlock condition
(i.e. prepare callback being called before subs->running is set).
Once when the flag is set, the period-elapsed call is handled at a
later URB complete call instead.
As a reference for the original motivation for the low-latency change,
I cite here again:
| USB-audio driver behaves a bit strangely for the playback stream --
| namely, it starts sending silent packets at PCM prepare state while
| the actual data is submitted at first when the trigger START is
| kicked off. This is a workaround for the behavior where URBs are
| processed too quickly at the beginning. That is, if we start
| submitting URBs at trigger START, the first few URBs will be
| immediately completed, and this would result in the immediate
| period-elapsed calls right after the start, which may confuse
| applications.
|
| OTOH, submitting the data after silent URBs would, of course, result
| in a certain delay of the actual data processing, and this is rather
| more serious problem on modern systems, in practice.
|
| This patch tries to revert the workaround and lets the URB
| submission starting at PCM trigger for the playback again. As far
| as I've tested with various backends (native ALSA, PA, JACK, PW), I
| haven't seen any problems (famous last words :)
|
| Note that the capture stream handling needs no such workaround,
| since the capture is driven per received URB.
Link: https://lore.kernel.org/r/4e71531f-4535-fd46-040e-506a3c256bbd@marcan.st
Link: https://lore.kernel.org/r/s5hbl7li0fe.wl-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/20210707112447.27485-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-07-07 11:24:47 +00:00
|
|
|
int err;
|
2012-04-12 11:51:12 +00:00
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case SNDRV_PCM_TRIGGER_START:
|
2015-02-06 21:55:53 +00:00
|
|
|
subs->trigger_tstamp_pending_update = true;
|
2020-07-08 20:32:36 +00:00
|
|
|
fallthrough;
|
2012-04-12 11:51:12 +00:00
|
|
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
ALSA: usb-audio: Set callbacks via snd_usb_endpoint_set_callback()
The prepare_data_urb and retire_data_urb fields of the endpoint object
are set dynamically at PCM trigger start/stop. Those are evaluated in
the endpoint handler, but there can be a race, especially if two
different PCM substreams are handling the same endpoint for the
implicit feedback case. Also, the data_subs field of the endpoint is
set and accessed dynamically, too, which has the same risk.
As a slight improvement for the concurrency, this patch introduces the
function to set the callbacks and the data in a shot with the memory
barrier. In the reader side, it's also fetched with the memory
barrier.
There is still a room of race if prepare and retire callbacks are set
during executing the URB completion. But such an inconsistency may
happen only for the implicit fb source, i.e. it's only about the
capture stream. And luckily, the capture stream never sets the
prepare callback, hence the problem doesn't happen practically.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-23-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:28 +00:00
|
|
|
snd_usb_endpoint_set_callback(subs->data_endpoint,
|
|
|
|
prepare_playback_urb,
|
|
|
|
retire_playback_urb,
|
|
|
|
subs);
|
2021-09-29 08:08:38 +00:00
|
|
|
if (subs->lowlatency_playback &&
|
ALSA: usb-audio: Work around for XRUN with low latency playback
The recent change for low latency playback works in most of test cases
but it turned out still to hit errors on some use cases, most notably
with JACK with small buffer sizes. This is because USB-audio driver
fills up and submits full URBs at the beginning, while the URBs would
return immediately and try to fill more -- that can easily trigger
XRUN. It was more or less expected, but in the small buffer size, the
problem became pretty obvious.
Fixing this behavior properly would require the change of the
fundamental driver design, so it's no trivial task, unfortunately.
Instead, here we work around the problem just by switching back to the
old method when the given configuration is too fragile with the low
latency stream handling. As a threshold, we calculate the total
buffer bytes in all plus one URBs, and check whether it's beyond the
PCM buffer bytes. The one extra URB is needed because XRUN happens at
the next submission after the first round.
Fixes: 307cc9baac5c ("ALSA: usb-audio: Reduce latency at playback start, take#2")
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20210827203311.5987-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-08-27 20:33:11 +00:00
|
|
|
cmd == SNDRV_PCM_TRIGGER_START) {
|
2021-11-19 10:24:59 +00:00
|
|
|
if (in_free_wheeling_mode(substream->runtime))
|
|
|
|
subs->lowlatency_playback = false;
|
ALSA: usb-audio: Reduce latency at playback start, take#2
This is another attempt for the reduction of the latency at the start
of a USB audio playback stream. The first attempt in the commit
9ce650a75a3b caused an unexpected regression (a deadlock with pipewire
usage) and was later reverted by the commit 4b820e167bf6. The devils
are always living in details, of course; the cause of the deadlock was
the call of snd_pcm_period_elapsed() inside prepare_playback_urb()
callback. In the original code, this callback is never called from
the stream lock context as it's driven solely from the URB complete
callback. Along with the movement of the URB submission into the
trigger START, this prepare call may be also executed in the stream
lock context, hence it deadlocked with the another lock in
snd_pcm_period_elapsed(). (Note that this happens only conditionally
with a small period size that matches with the URB buffer length,
which was a reason I overlooked during my tests. Also, the problem
wasn't seen in the capture stream because the capture stream handles
the period-elapsed only at retire callback that isn't executed at the
trigger.)
If it were only about avoiding the deadlock, it'd be possible to use
snd_pcm_period_elapsed_under_stream_lock() as a solution. However, in
general, the period elapsed notification must be sent after the actual
stream start, and replacing the call wouldn't satisfy the pattern.
A better option is to delay the notification after the stream start
procedure finished, instead. In the case of USB framework, one of the
fitting place would be the complete callback of the first URB.
So, as a workaround of the deadlock and the order fixes above, in
addition to the re-applying the changes in the commit 9ce650a75a3,
this patch introduces a new flag indicating the delayed period-elapsed
handling and sets it under the possible deadlock condition
(i.e. prepare callback being called before subs->running is set).
Once when the flag is set, the period-elapsed call is handled at a
later URB complete call instead.
As a reference for the original motivation for the low-latency change,
I cite here again:
| USB-audio driver behaves a bit strangely for the playback stream --
| namely, it starts sending silent packets at PCM prepare state while
| the actual data is submitted at first when the trigger START is
| kicked off. This is a workaround for the behavior where URBs are
| processed too quickly at the beginning. That is, if we start
| submitting URBs at trigger START, the first few URBs will be
| immediately completed, and this would result in the immediate
| period-elapsed calls right after the start, which may confuse
| applications.
|
| OTOH, submitting the data after silent URBs would, of course, result
| in a certain delay of the actual data processing, and this is rather
| more serious problem on modern systems, in practice.
|
| This patch tries to revert the workaround and lets the URB
| submission starting at PCM trigger for the playback again. As far
| as I've tested with various backends (native ALSA, PA, JACK, PW), I
| haven't seen any problems (famous last words :)
|
| Note that the capture stream handling needs no such workaround,
| since the capture is driven per received URB.
Link: https://lore.kernel.org/r/4e71531f-4535-fd46-040e-506a3c256bbd@marcan.st
Link: https://lore.kernel.org/r/s5hbl7li0fe.wl-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/20210707112447.27485-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-07-07 11:24:47 +00:00
|
|
|
err = start_endpoints(subs);
|
|
|
|
if (err < 0) {
|
|
|
|
snd_usb_endpoint_set_callback(subs->data_endpoint,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
2012-05-21 10:47:36 +00:00
|
|
|
subs->running = 1;
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
dev_dbg(&subs->dev->dev, "%d:%d Start Playback PCM\n",
|
|
|
|
subs->cur_audiofmt->iface,
|
|
|
|
subs->cur_audiofmt->altsetting);
|
2012-04-12 11:51:12 +00:00
|
|
|
return 0;
|
2020-11-23 08:53:29 +00:00
|
|
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
2012-04-12 11:51:12 +00:00
|
|
|
case SNDRV_PCM_TRIGGER_STOP:
|
2022-09-26 13:55:54 +00:00
|
|
|
stop_endpoints(subs, substream->runtime->state == SNDRV_PCM_STATE_DRAINING);
|
ALSA: usb-audio: Set callbacks via snd_usb_endpoint_set_callback()
The prepare_data_urb and retire_data_urb fields of the endpoint object
are set dynamically at PCM trigger start/stop. Those are evaluated in
the endpoint handler, but there can be a race, especially if two
different PCM substreams are handling the same endpoint for the
implicit feedback case. Also, the data_subs field of the endpoint is
set and accessed dynamically, too, which has the same risk.
As a slight improvement for the concurrency, this patch introduces the
function to set the callbacks and the data in a shot with the memory
barrier. In the reader side, it's also fetched with the memory
barrier.
There is still a room of race if prepare and retire callbacks are set
during executing the URB completion. But such an inconsistency may
happen only for the implicit fb source, i.e. it's only about the
capture stream. And luckily, the capture stream never sets the
prepare callback, hence the problem doesn't happen practically.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-23-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:28 +00:00
|
|
|
snd_usb_endpoint_set_callback(subs->data_endpoint,
|
|
|
|
NULL, NULL, NULL);
|
2012-05-21 10:47:36 +00:00
|
|
|
subs->running = 0;
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
dev_dbg(&subs->dev->dev, "%d:%d Stop Playback PCM\n",
|
|
|
|
subs->cur_audiofmt->iface,
|
|
|
|
subs->cur_audiofmt->altsetting);
|
2012-04-12 11:51:12 +00:00
|
|
|
return 0;
|
|
|
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
2012-11-23 15:00:37 +00:00
|
|
|
/* keep retire_data_urb for delay calculation */
|
ALSA: usb-audio: Set callbacks via snd_usb_endpoint_set_callback()
The prepare_data_urb and retire_data_urb fields of the endpoint object
are set dynamically at PCM trigger start/stop. Those are evaluated in
the endpoint handler, but there can be a race, especially if two
different PCM substreams are handling the same endpoint for the
implicit feedback case. Also, the data_subs field of the endpoint is
set and accessed dynamically, too, which has the same risk.
As a slight improvement for the concurrency, this patch introduces the
function to set the callbacks and the data in a shot with the memory
barrier. In the reader side, it's also fetched with the memory
barrier.
There is still a room of race if prepare and retire callbacks are set
during executing the URB completion. But such an inconsistency may
happen only for the implicit fb source, i.e. it's only about the
capture stream. And luckily, the capture stream never sets the
prepare callback, hence the problem doesn't happen practically.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-23-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:28 +00:00
|
|
|
snd_usb_endpoint_set_callback(subs->data_endpoint,
|
|
|
|
NULL,
|
|
|
|
retire_playback_urb,
|
|
|
|
subs);
|
2012-05-21 10:47:36 +00:00
|
|
|
subs->running = 0;
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
dev_dbg(&subs->dev->dev, "%d:%d Pause Playback PCM\n",
|
|
|
|
subs->cur_audiofmt->iface,
|
|
|
|
subs->cur_audiofmt->altsetting);
|
2012-04-12 11:51:12 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2012-06-16 14:58:04 +00:00
|
|
|
static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream,
|
|
|
|
int cmd)
|
2012-04-12 11:51:12 +00:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
struct snd_usb_substream *subs = substream->runtime->private_data;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case SNDRV_PCM_TRIGGER_START:
|
2017-01-04 22:37:46 +00:00
|
|
|
err = start_endpoints(subs);
|
2012-04-12 11:51:12 +00:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
ALSA: usb-audio: Set callbacks via snd_usb_endpoint_set_callback()
The prepare_data_urb and retire_data_urb fields of the endpoint object
are set dynamically at PCM trigger start/stop. Those are evaluated in
the endpoint handler, but there can be a race, especially if two
different PCM substreams are handling the same endpoint for the
implicit feedback case. Also, the data_subs field of the endpoint is
set and accessed dynamically, too, which has the same risk.
As a slight improvement for the concurrency, this patch introduces the
function to set the callbacks and the data in a shot with the memory
barrier. In the reader side, it's also fetched with the memory
barrier.
There is still a room of race if prepare and retire callbacks are set
during executing the URB completion. But such an inconsistency may
happen only for the implicit fb source, i.e. it's only about the
capture stream. And luckily, the capture stream never sets the
prepare callback, hence the problem doesn't happen practically.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-23-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:28 +00:00
|
|
|
fallthrough;
|
|
|
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
|
|
|
snd_usb_endpoint_set_callback(subs->data_endpoint,
|
|
|
|
NULL, retire_capture_urb,
|
|
|
|
subs);
|
ALSA: usb-audio: Refactoring delay account code
The PCM delay accounting in USB-audio driver is a bit complex to
follow, and this is an attempt to improve the readability and provide
some potential fix.
Basically, the PCM position delay is calculated from two factors: the
in-flight data on URBs and the USB frame counter. For the playback
stream, we advance the hwptr already at submitting URBs. Those
"in-flight" data amount is now tracked, and this is used as the base
value for the PCM delay correction. The in-flight data is decreased
again at URB completion in return. For the capture stream, OTOH,
there is no in-flight data, hence the delay base is zero.
The USB frame counter is used in addition for correcting the current
position. The reference frame counter is updated at each submission
and receiving time, and the difference from the current counter value
is taken into account.
In this patch, each in-flight data bytes is recorded in the new
snd_usb_ctx.queued field, and the total in-flight amount is tracked in
snd_usb_substream.inflight_bytes field, as the replacement of
last_delay field.
Note that updating the hwptr after URB completion doesn't work for
PulseAudio who tries to scratch the buffer on the fly; USB-audio is
basically a double-buffer implementation, hence the scratching the
buffer can't work for the already submitted data. So we always update
hwptr beforehand. It's not ideal, but the delay account should give
enough correctness.
Link: https://lore.kernel.org/r/20210601162457.4877-4-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-06-01 16:24:55 +00:00
|
|
|
subs->last_frame_number = usb_get_current_frame_number(subs->dev);
|
2012-05-21 10:47:36 +00:00
|
|
|
subs->running = 1;
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
dev_dbg(&subs->dev->dev, "%d:%d Start Capture PCM\n",
|
|
|
|
subs->cur_audiofmt->iface,
|
|
|
|
subs->cur_audiofmt->altsetting);
|
2012-04-12 11:51:12 +00:00
|
|
|
return 0;
|
2020-11-23 08:53:29 +00:00
|
|
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
2012-04-12 11:51:12 +00:00
|
|
|
case SNDRV_PCM_TRIGGER_STOP:
|
2021-09-29 08:08:44 +00:00
|
|
|
stop_endpoints(subs, false);
|
ALSA: usb-audio: Set callbacks via snd_usb_endpoint_set_callback()
The prepare_data_urb and retire_data_urb fields of the endpoint object
are set dynamically at PCM trigger start/stop. Those are evaluated in
the endpoint handler, but there can be a race, especially if two
different PCM substreams are handling the same endpoint for the
implicit feedback case. Also, the data_subs field of the endpoint is
set and accessed dynamically, too, which has the same risk.
As a slight improvement for the concurrency, this patch introduces the
function to set the callbacks and the data in a shot with the memory
barrier. In the reader side, it's also fetched with the memory
barrier.
There is still a room of race if prepare and retire callbacks are set
during executing the URB completion. But such an inconsistency may
happen only for the implicit fb source, i.e. it's only about the
capture stream. And luckily, the capture stream never sets the
prepare callback, hence the problem doesn't happen practically.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-23-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:28 +00:00
|
|
|
fallthrough;
|
2012-04-12 11:51:12 +00:00
|
|
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
ALSA: usb-audio: Set callbacks via snd_usb_endpoint_set_callback()
The prepare_data_urb and retire_data_urb fields of the endpoint object
are set dynamically at PCM trigger start/stop. Those are evaluated in
the endpoint handler, but there can be a race, especially if two
different PCM substreams are handling the same endpoint for the
implicit feedback case. Also, the data_subs field of the endpoint is
set and accessed dynamically, too, which has the same risk.
As a slight improvement for the concurrency, this patch introduces the
function to set the callbacks and the data in a shot with the memory
barrier. In the reader side, it's also fetched with the memory
barrier.
There is still a room of race if prepare and retire callbacks are set
during executing the URB completion. But such an inconsistency may
happen only for the implicit fb source, i.e. it's only about the
capture stream. And luckily, the capture stream never sets the
prepare callback, hence the problem doesn't happen practically.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-23-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:28 +00:00
|
|
|
snd_usb_endpoint_set_callback(subs->data_endpoint,
|
|
|
|
NULL, NULL, NULL);
|
2012-05-21 10:47:36 +00:00
|
|
|
subs->running = 0;
|
ALSA: usb-audio: Refactor endpoint management
This is an intensive surgery for the endpoint and stream management
for achieving more robust and clean code.
The goals of this patch are:
- More clear endpoint resource changes
- The interface altsetting control in a single place
Below are brief description of the whole changes.
First off, most of the endpoint operations are moved into endpoint.c,
so that the snd_usb_endpoint object is only referred in other places.
The endpoint object is acquired and released via the new functions
snd_usb_endpoint_open() and snd_usb_endpoint_close() that are called
at PCM hw_params and hw_free callbacks, respectively. Those are
ref-counted and EPs can manage the multiple opens.
The open callback receives the audioformat and hw_params arguments,
and those are used for initializing the EP parameters; especially the
endpoint, interface and altset numbers are read from there, as well as
the PCM parameters like the format, rate and channels. Those are
stored in snd_usb_endpoint object. If it's the secondary open, the
function checks whether the given parameters are compatible with the
already opened EP setup, too.
The coupling with a sync EP (including an implicit feedback sync) is
done by the sole snd_usb_endpoint_set_sync() call.
The configuration of each endpoint is done in a single shot via
snd_usb_endpoint_configure() call. This is the place where most of
PCM configurations are done. A few flags and special handling in the
snd_usb_substream are dropped along with this change.
A significant difference wrt the configuration from the previous code
is the order of USB host interface setups. Now the interface is
always disabled at beginning and (re-)enabled at the last step of
snd_usb_endpoint_configure(), in order to be compliant with the
standard UAC2/3. For UAC1, the interface is set before the parameter
setups since there seem devices that require it (e.g. Yamaha THR10),
just like how it was done in the previous driver code.
The start/stop are almost same as before, also single-shots. The URB
callbacks need to be set via snd_usb_endpoint_set_callback() like the
previous code at the trigger phase, too.
Finally, the flag for the re-setup is set at the device suspend
through the full EP list, instead of PCM trigger. This catches the
overlooked cases where the PCM hasn't been running yet but the device
needs the full setup after resume.
Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-26-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2020-11-23 08:53:31 +00:00
|
|
|
dev_dbg(&subs->dev->dev, "%d:%d Stop Capture PCM\n",
|
|
|
|
subs->cur_audiofmt->iface,
|
|
|
|
subs->cur_audiofmt->altsetting);
|
2012-04-12 11:51:12 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2017-08-18 07:45:21 +00:00
|
|
|
static const struct snd_pcm_ops snd_usb_playback_ops = {
|
2018-05-27 11:59:03 +00:00
|
|
|
.open = snd_usb_pcm_open,
|
|
|
|
.close = snd_usb_pcm_close,
|
2010-03-04 18:46:13 +00:00
|
|
|
.hw_params = snd_usb_hw_params,
|
|
|
|
.hw_free = snd_usb_hw_free,
|
|
|
|
.prepare = snd_usb_pcm_prepare,
|
|
|
|
.trigger = snd_usb_substream_playback_trigger,
|
2019-12-10 06:34:54 +00:00
|
|
|
.sync_stop = snd_usb_pcm_sync_stop,
|
2010-03-04 18:46:13 +00:00
|
|
|
.pointer = snd_usb_pcm_pointer,
|
ALSA: usb-audio: Improved lowlatency playback support
This is another attempt to improve further the handling of playback
stream in the low latency mode. The latest workaround in commit
4267c5a8f313 ("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: 4267c5a8f313 ("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>
2021-09-29 08:08:43 +00:00
|
|
|
.ack = snd_usb_pcm_playback_ack,
|
2010-03-04 18:46:13 +00:00
|
|
|
};
|
|
|
|
|
2017-08-18 07:45:21 +00:00
|
|
|
static const struct snd_pcm_ops snd_usb_capture_ops = {
|
2018-05-27 11:59:03 +00:00
|
|
|
.open = snd_usb_pcm_open,
|
|
|
|
.close = snd_usb_pcm_close,
|
2010-03-04 18:46:13 +00:00
|
|
|
.hw_params = snd_usb_hw_params,
|
|
|
|
.hw_free = snd_usb_hw_free,
|
|
|
|
.prepare = snd_usb_pcm_prepare,
|
|
|
|
.trigger = snd_usb_substream_capture_trigger,
|
2019-12-10 06:34:54 +00:00
|
|
|
.sync_stop = snd_usb_pcm_sync_stop,
|
2010-03-04 18:46:13 +00:00
|
|
|
.pointer = snd_usb_pcm_pointer,
|
2018-05-27 11:01:17 +00:00
|
|
|
};
|
|
|
|
|
2010-03-04 18:46:13 +00:00
|
|
|
void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream)
|
|
|
|
{
|
2018-05-27 11:01:17 +00:00
|
|
|
const struct snd_pcm_ops *ops;
|
|
|
|
|
2019-11-05 15:18:40 +00:00
|
|
|
ops = stream == SNDRV_PCM_STREAM_PLAYBACK ?
|
2018-05-27 11:01:17 +00:00
|
|
|
&snd_usb_playback_ops : &snd_usb_capture_ops;
|
|
|
|
snd_pcm_set_ops(pcm, stream, ops);
|
|
|
|
}
|
|
|
|
|
|
|
|
void snd_usb_preallocate_buffer(struct snd_usb_substream *subs)
|
|
|
|
{
|
|
|
|
struct snd_pcm *pcm = subs->stream->pcm;
|
|
|
|
struct snd_pcm_substream *s = pcm->streams[subs->direction].substream;
|
2021-02-05 14:45:59 +00:00
|
|
|
struct device *dev = subs->dev->bus->sysdev;
|
2018-05-27 11:01:17 +00:00
|
|
|
|
2019-11-05 15:18:40 +00:00
|
|
|
if (snd_usb_use_vmalloc)
|
2019-12-09 09:49:42 +00:00
|
|
|
snd_pcm_set_managed_buffer(s, SNDRV_DMA_TYPE_VMALLOC,
|
|
|
|
NULL, 0, 0);
|
2019-11-05 15:18:40 +00:00
|
|
|
else
|
2019-12-09 09:49:42 +00:00
|
|
|
snd_pcm_set_managed_buffer(s, SNDRV_DMA_TYPE_DEV_SG,
|
|
|
|
dev, 64*1024, 512*1024);
|
2010-03-04 18:46:13 +00:00
|
|
|
}
|