diff mbox series

[v24,23/34] ALSA: usb-audio: Prevent starting of audio stream if in use

Message ID 20240801011730.4797-24-quic_wcheng@quicinc.com
State Superseded
Headers show
Series Introduce QC USB SND audio offloading support | expand

Commit Message

Wesley Cheng Aug. 1, 2024, 1:17 a.m. UTC
With USB audio offloading, an audio session is started from the ASoC
platform sound card and PCM devices.  Likewise, the USB SND path is still
readily available for use, in case the non-offload path is desired.  In
order to prevent the two entities from attempting to use the USB bus,
introduce a flag that determines when either paths are in use.

If a PCM device is already in use, the check will return an error to
userspace notifying that the stream is currently busy.  This ensures that
only one path is using the USB substream.

Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com>
---
 sound/usb/card.h |  1 +
 sound/usb/pcm.c  | 29 ++++++++++++++++++++++++++---
 2 files changed, 27 insertions(+), 3 deletions(-)

Comments

Amadeusz Sławiński Aug. 6, 2024, 2:51 p.m. UTC | #1
On 8/1/2024 3:17 AM, Wesley Cheng wrote:
> With USB audio offloading, an audio session is started from the ASoC
> platform sound card and PCM devices.  Likewise, the USB SND path is still
> readily available for use, in case the non-offload path is desired.  In
> order to prevent the two entities from attempting to use the USB bus,
> introduce a flag that determines when either paths are in use.
> 

How can this happen? Can you provide some example with list of devices 
and which one should block the other? If I recall correctly devices are 
already exclusive unless you support substreams which ASoC does not at 
the moment.
Wesley Cheng Aug. 8, 2024, 1:19 a.m. UTC | #2
Hi Amadeusz,

On 8/6/2024 7:51 AM, Amadeusz Sławiński wrote:
> On 8/1/2024 3:17 AM, Wesley Cheng wrote:
>> With USB audio offloading, an audio session is started from the ASoC
>> platform sound card and PCM devices.  Likewise, the USB SND path is still
>> readily available for use, in case the non-offload path is desired.  In
>> order to prevent the two entities from attempting to use the USB bus,
>> introduce a flag that determines when either paths are in use.
>>
>
> How can this happen? Can you provide some example with list of devices and which one should block the other? If I recall correctly devices are already exclusive unless you support substreams which ASoC does not at the moment.
>
>From past discussions, I think so far everyone is on board with the idea of having both the USB sound card and PCM devices exist in conjunction w/ the USB offload path, which is going to be done over the ASoC platform card.  So for example,

/ # cat /proc/asound/cards
 0 [SM8250MTPWCD938]: sm8250 - SM8250-MTP-WCD9380-WSA8810-VA-D
                      SM8250-MTP-WCD9380-WSA8810-VA-DMIC
 1 [C320M          ]: USB-Audio - Plantronics C320-M
                      Plantronics Plantronics C320-M at usb-xhci-hcd.1.auto-1.2, full speed

This device currently has the following sound cards within the system:

- card#0 - ASoC platform card: handles USB offload, speaker, etc...

- card#1 - USB SND card: card created for interacting with the connected USB device.

So now, with USB offloading in the picture, there are basically two paths that can start attempting to utilize the same USB device endpoints.  Let's keep it simple and assume the device only has one playback substream (which means only one PCM device)

/proc/asound/card1 # cat stream0
Plantronics Plantronics C320-M at usb-xhci-hcd.1.auto-1.2, full speed : USB Audio

Playback:
  Status: Stop
  Interface 2
    Altset 1
    Format: S16_LE
    Channels: 2
    Endpoint: 0x01 (1 OUT) (ADAPTIVE)
    Rates: 8000, 16000, 24000, 32000, 44100, 48000
    Bits: 16
    Channel map: FL FR

So the patch here will prevent transfers from happening from both the offload path and directly over the USB SND PCM device, which correlates to the following paths:

- offload: card#0 pcm#0

- USB SND: card#1 pcm#0

Thanks

Wesley Cheng
Amadeusz Sławiński Aug. 8, 2024, 12:11 p.m. UTC | #3
On 8/8/2024 3:19 AM, Wesley Cheng wrote:
> Hi Amadeusz,
> 
> On 8/6/2024 7:51 AM, Amadeusz Sławiński wrote:
>> On 8/1/2024 3:17 AM, Wesley Cheng wrote:
>>> With USB audio offloading, an audio session is started from the ASoC
>>> platform sound card and PCM devices.  Likewise, the USB SND path is still
>>> readily available for use, in case the non-offload path is desired.  In
>>> order to prevent the two entities from attempting to use the USB bus,
>>> introduce a flag that determines when either paths are in use.
>>>
>>
>> How can this happen? Can you provide some example with list of devices and which one should block the other? If I recall correctly devices are already exclusive unless you support substreams which ASoC does not at the moment.
>>
>  From past discussions, I think so far everyone is on board with the idea of having both the USB sound card and PCM devices exist in conjunction w/ the USB offload path, which is going to be done over the ASoC platform card.  So for example,
> 

Sorry, I must have missed that and examples in documentation could 
probably be a bit better, it is bit late at patchset 24 that I 
understood about this now. And is part of a reason why I was confused 
about kcontrol implementation.

> / # cat /proc/asound/cards
>   0 [SM8250MTPWCD938]: sm8250 - SM8250-MTP-WCD9380-WSA8810-VA-D
>                        SM8250-MTP-WCD9380-WSA8810-VA-DMIC
>   1 [C320M          ]: USB-Audio - Plantronics C320-M
>                        Plantronics Plantronics C320-M at usb-xhci-hcd.1.auto-1.2, full speed
> 
> This device currently has the following sound cards within the system:
> 
> - card#0 - ASoC platform card: handles USB offload, speaker, etc...
> 
> - card#1 - USB SND card: card created for interacting with the connected USB device.
> 
> So now, with USB offloading in the picture, there are basically two paths that can start attempting to utilize the same USB device endpoints.  Let's keep it simple and assume the device only has one playback substream (which means only one PCM device)
> 
> /proc/asound/card1 # cat stream0
> Plantronics Plantronics C320-M at usb-xhci-hcd.1.auto-1.2, full speed : USB Audio
> 
> Playback:
>    Status: Stop
>    Interface 2
>      Altset 1
>      Format: S16_LE
>      Channels: 2
>      Endpoint: 0x01 (1 OUT) (ADAPTIVE)
>      Rates: 8000, 16000, 24000, 32000, 44100, 48000
>      Bits: 16
>      Channel map: FL FR
> 
> So the patch here will prevent transfers from happening from both the offload path and directly over the USB SND PCM device, which correlates to the following paths:
> 
> - offload: card#0 pcm#0
> 
> - USB SND: card#1 pcm#0

Well, it's one way to do that.

Personally I would just reuse USB FEs and when opening one check if it 
can be offloaded:
* check if someone disabled Offload on FE
* check if it is connected to HW that can do Offload at all
* check if Offload streams are available on backing HW
* check if audio formats are supported by above HW
* do any other checks that may be needed
and then just redirect FE setup to relevant driver doing offload if 
able, otherwise just go standard path.


As I've wrote I must have missed the discussion where it was agreed on 
and if maintainers agree that it can be done this way, I won't fight it. 
Even though I would consider my way a lot simpler and user friendly from 
end user point of view.

Thanks,
Amadeusz
Pierre-Louis Bossart Aug. 8, 2024, 12:36 p.m. UTC | #4
On 8/8/24 14:11, Amadeusz Sławiński wrote:
> On 8/8/2024 3:19 AM, Wesley Cheng wrote:
>> Hi Amadeusz,
>>
>> On 8/6/2024 7:51 AM, Amadeusz Sławiński wrote:
>>> On 8/1/2024 3:17 AM, Wesley Cheng wrote:
>>>> With USB audio offloading, an audio session is started from the ASoC
>>>> platform sound card and PCM devices.  Likewise, the USB SND path is
>>>> still
>>>> readily available for use, in case the non-offload path is desired.  In
>>>> order to prevent the two entities from attempting to use the USB bus,
>>>> introduce a flag that determines when either paths are in use.
>>>>
>>>
>>> How can this happen? Can you provide some example with list of
>>> devices and which one should block the other? If I recall correctly
>>> devices are already exclusive unless you support substreams which
>>> ASoC does not at the moment.
>>>
>>  From past discussions, I think so far everyone is on board with the
>> idea of having both the USB sound card and PCM devices exist in
>> conjunction w/ the USB offload path, which is going to be done over
>> the ASoC platform card.  So for example,
>>
> 
> Sorry, I must have missed that and examples in documentation could
> probably be a bit better, it is bit late at patchset 24 that I
> understood about this now. And is part of a reason why I was confused
> about kcontrol implementation.
> 
>> / # cat /proc/asound/cards
>>   0 [SM8250MTPWCD938]: sm8250 - SM8250-MTP-WCD9380-WSA8810-VA-D
>>                        SM8250-MTP-WCD9380-WSA8810-VA-DMIC
>>   1 [C320M          ]: USB-Audio - Plantronics C320-M
>>                        Plantronics Plantronics C320-M at usb-xhci-
>> hcd.1.auto-1.2, full speed
>>
>> This device currently has the following sound cards within the system:
>>
>> - card#0 - ASoC platform card: handles USB offload, speaker, etc...
>>
>> - card#1 - USB SND card: card created for interacting with the
>> connected USB device.
>>
>> So now, with USB offloading in the picture, there are basically two
>> paths that can start attempting to utilize the same USB device
>> endpoints.  Let's keep it simple and assume the device only has one
>> playback substream (which means only one PCM device)
>>
>> /proc/asound/card1 # cat stream0
>> Plantronics Plantronics C320-M at usb-xhci-hcd.1.auto-1.2, full
>> speed : USB Audio
>>
>> Playback:
>>    Status: Stop
>>    Interface 2
>>      Altset 1
>>      Format: S16_LE
>>      Channels: 2
>>      Endpoint: 0x01 (1 OUT) (ADAPTIVE)
>>      Rates: 8000, 16000, 24000, 32000, 44100, 48000
>>      Bits: 16
>>      Channel map: FL FR
>>
>> So the patch here will prevent transfers from happening from both the
>> offload path and directly over the USB SND PCM device, which
>> correlates to the following paths:
>>
>> - offload: card#0 pcm#0
>>
>> - USB SND: card#1 pcm#0
> 
> Well, it's one way to do that.
> 
> Personally I would just reuse USB FEs and when opening one check if it
> can be offloaded:
> * check if someone disabled Offload on FE
> * check if it is connected to HW that can do Offload at all
> * check if Offload streams are available on backing HW
> * check if audio formats are supported by above HW
> * do any other checks that may be needed
> and then just redirect FE setup to relevant driver doing offload if
> able, otherwise just go standard path.

How would userspace know which 'USB FE' to use?

The discovery and mapping between cards and devices is the main problem.

It's much simpler to start from a generic "USB-Audio" card, and check if
the functionality exposed by one PCM device is offloaded to another
ASoC-based card. Then all the interaction can start with this offloaded
device without any guesswork on the mapping between cards/devices.

The point is that the USB-Audio card will always be there, whereas those
ASoC cards will have different names and implementation restrictions. In
the example we have here, if you want to capture audio you *have* to use
the USB-Audio card.

In other words, it's just an endianness type of debate with no clear
difference between solutions and a matter of personal preference. The
reality is that there's a clear asymmetrical pattern. The USB-Audio card
is always present and usable, the ASoC offloaded cards are only present
in specific implementations and only usable if conditions are met.
Amadeusz Sławiński Aug. 8, 2024, 2:54 p.m. UTC | #5
On 8/8/2024 2:36 PM, Pierre-Louis Bossart wrote:
> 
> 
> On 8/8/24 14:11, Amadeusz Sławiński wrote:
>> On 8/8/2024 3:19 AM, Wesley Cheng wrote:
>>> Hi Amadeusz,
>>>
>>> On 8/6/2024 7:51 AM, Amadeusz Sławiński wrote:
>>>> On 8/1/2024 3:17 AM, Wesley Cheng wrote:
>>>>> With USB audio offloading, an audio session is started from the ASoC
>>>>> platform sound card and PCM devices.  Likewise, the USB SND path is
>>>>> still
>>>>> readily available for use, in case the non-offload path is desired.  In
>>>>> order to prevent the two entities from attempting to use the USB bus,
>>>>> introduce a flag that determines when either paths are in use.
>>>>>
>>>>
>>>> How can this happen? Can you provide some example with list of
>>>> devices and which one should block the other? If I recall correctly
>>>> devices are already exclusive unless you support substreams which
>>>> ASoC does not at the moment.
>>>>
>>>   From past discussions, I think so far everyone is on board with the
>>> idea of having both the USB sound card and PCM devices exist in
>>> conjunction w/ the USB offload path, which is going to be done over
>>> the ASoC platform card.  So for example,
>>>
>>
>> Sorry, I must have missed that and examples in documentation could
>> probably be a bit better, it is bit late at patchset 24 that I
>> understood about this now. And is part of a reason why I was confused
>> about kcontrol implementation.
>>
>>> / # cat /proc/asound/cards
>>>    0 [SM8250MTPWCD938]: sm8250 - SM8250-MTP-WCD9380-WSA8810-VA-D
>>>                         SM8250-MTP-WCD9380-WSA8810-VA-DMIC
>>>    1 [C320M          ]: USB-Audio - Plantronics C320-M
>>>                         Plantronics Plantronics C320-M at usb-xhci-
>>> hcd.1.auto-1.2, full speed
>>>
>>> This device currently has the following sound cards within the system:
>>>
>>> - card#0 - ASoC platform card: handles USB offload, speaker, etc...
>>>
>>> - card#1 - USB SND card: card created for interacting with the
>>> connected USB device.
>>>
>>> So now, with USB offloading in the picture, there are basically two
>>> paths that can start attempting to utilize the same USB device
>>> endpoints.  Let's keep it simple and assume the device only has one
>>> playback substream (which means only one PCM device)
>>>
>>> /proc/asound/card1 # cat stream0
>>> Plantronics Plantronics C320-M at usb-xhci-hcd.1.auto-1.2, full
>>> speed : USB Audio
>>>
>>> Playback:
>>>     Status: Stop
>>>     Interface 2
>>>       Altset 1
>>>       Format: S16_LE
>>>       Channels: 2
>>>       Endpoint: 0x01 (1 OUT) (ADAPTIVE)
>>>       Rates: 8000, 16000, 24000, 32000, 44100, 48000
>>>       Bits: 16
>>>       Channel map: FL FR
>>>
>>> So the patch here will prevent transfers from happening from both the
>>> offload path and directly over the USB SND PCM device, which
>>> correlates to the following paths:
>>>
>>> - offload: card#0 pcm#0
>>>
>>> - USB SND: card#1 pcm#0
>>
>> Well, it's one way to do that.
>>
>> Personally I would just reuse USB FEs and when opening one check if it
>> can be offloaded:
>> * check if someone disabled Offload on FE
>> * check if it is connected to HW that can do Offload at all
>> * check if Offload streams are available on backing HW
>> * check if audio formats are supported by above HW
>> * do any other checks that may be needed
>> and then just redirect FE setup to relevant driver doing offload if
>> able, otherwise just go standard path.
> 
> How would userspace know which 'USB FE' to use?
> 

That's my point, the same one as it would use doing normal 
playback/capture on systems which don't have Offload.

If I attach USB Headphones, as a user my expectation would be to use 
playback FE on USB card it exposes, not to spend time setting some 
controls and telling it to use some FE from other card.

With current design there are _two_ separate FEs, on _two_ separate 
cards, which are linked by kcontrol and which block each other. I'm 
rather confused how basic userspace application knows which one to use 
in this case. (By now of course I know that it needs to read kcontrol to 
see if and where it is offloaded and then open the FE on the card, but 
in my opinion it is unnecessarily convoluted.)

> The discovery and mapping between cards and devices is the main problem.
> 

And "offloading" decision to the user/sound server/HAL doesn't help in 
my opinion.

> It's much simpler to start from a generic "USB-Audio" card, and check if
> the functionality exposed by one PCM device is offloaded to another
> ASoC-based card. Then all the interaction can start with this offloaded
> device without any guesswork on the mapping between cards/devices.
> 

That's the point, currently there needs to be some guesswork involved, 
because you need to check kcontrols to see if the endpoint can be 
offloaded and open the other FE it points at, instead of directly 
opening the one you usually would, and having it Offloaded by kernel. It 
is adding more work on userspace side, which will require special 
handling to work correctly.

> The point is that the USB-Audio card will always be there, whereas those
> ASoC cards will have different names and implementation restrictions. In
> the example we have here, if you want to capture audio you *have* to use
> the USB-Audio card.
> 

Yes and with the description above it would be just one of the checks 
after which it would decide that it can't do Offload on capture path and 
open it in standard way, I see no problem?

> In other words, it's just an endianness type of debate with no clear
> difference between solutions and a matter of personal preference. The
> reality is that there's a clear asymmetrical pattern. The USB-Audio card
> is always present and usable, the ASoC offloaded cards are only present
> in specific implementations and only usable if conditions are met.

In my opinion even if it is specific use case, there is no reason to 
make it more complicated than it needs to be. From my point of view 
problem with current design is that instead of being mostly transparent 
to userspace (when it could be), it adds more work for it.
Wesley Cheng Aug. 8, 2024, 7:47 p.m. UTC | #6
On 8/8/2024 7:54 AM, Amadeusz Sławiński wrote:
> On 8/8/2024 2:36 PM, Pierre-Louis Bossart wrote:
>>
>>
>> On 8/8/24 14:11, Amadeusz Sławiński wrote:
>>> On 8/8/2024 3:19 AM, Wesley Cheng wrote:
>>>> Hi Amadeusz,
>>>>
>>>> On 8/6/2024 7:51 AM, Amadeusz Sławiński wrote:
>>>>> On 8/1/2024 3:17 AM, Wesley Cheng wrote:
>>>>>> With USB audio offloading, an audio session is started from the ASoC
>>>>>> platform sound card and PCM devices.  Likewise, the USB SND path is
>>>>>> still
>>>>>> readily available for use, in case the non-offload path is desired.  In
>>>>>> order to prevent the two entities from attempting to use the USB bus,
>>>>>> introduce a flag that determines when either paths are in use.
>>>>>>
>>>>>
>>>>> How can this happen? Can you provide some example with list of
>>>>> devices and which one should block the other? If I recall correctly
>>>>> devices are already exclusive unless you support substreams which
>>>>> ASoC does not at the moment.
>>>>>
>>>>   From past discussions, I think so far everyone is on board with the
>>>> idea of having both the USB sound card and PCM devices exist in
>>>> conjunction w/ the USB offload path, which is going to be done over
>>>> the ASoC platform card.  So for example,
>>>>
>>>
>>> Sorry, I must have missed that and examples in documentation could
>>> probably be a bit better, it is bit late at patchset 24 that I
>>> understood about this now. And is part of a reason why I was confused
>>> about kcontrol implementation.
>>>
>>>> / # cat /proc/asound/cards
>>>>    0 [SM8250MTPWCD938]: sm8250 - SM8250-MTP-WCD9380-WSA8810-VA-D
>>>>                         SM8250-MTP-WCD9380-WSA8810-VA-DMIC
>>>>    1 [C320M          ]: USB-Audio - Plantronics C320-M
>>>>                         Plantronics Plantronics C320-M at usb-xhci-
>>>> hcd.1.auto-1.2, full speed
>>>>
>>>> This device currently has the following sound cards within the system:
>>>>
>>>> - card#0 - ASoC platform card: handles USB offload, speaker, etc...
>>>>
>>>> - card#1 - USB SND card: card created for interacting with the
>>>> connected USB device.
>>>>
>>>> So now, with USB offloading in the picture, there are basically two
>>>> paths that can start attempting to utilize the same USB device
>>>> endpoints.  Let's keep it simple and assume the device only has one
>>>> playback substream (which means only one PCM device)
>>>>
>>>> /proc/asound/card1 # cat stream0
>>>> Plantronics Plantronics C320-M at usb-xhci-hcd.1.auto-1.2, full
>>>> speed : USB Audio
>>>>
>>>> Playback:
>>>>     Status: Stop
>>>>     Interface 2
>>>>       Altset 1
>>>>       Format: S16_LE
>>>>       Channels: 2
>>>>       Endpoint: 0x01 (1 OUT) (ADAPTIVE)
>>>>       Rates: 8000, 16000, 24000, 32000, 44100, 48000
>>>>       Bits: 16
>>>>       Channel map: FL FR
>>>>
>>>> So the patch here will prevent transfers from happening from both the
>>>> offload path and directly over the USB SND PCM device, which
>>>> correlates to the following paths:
>>>>
>>>> - offload: card#0 pcm#0
>>>>
>>>> - USB SND: card#1 pcm#0
>>>
>>> Well, it's one way to do that.
>>>
>>> Personally I would just reuse USB FEs and when opening one check if it
>>> can be offloaded:
>>> * check if someone disabled Offload on FE
>>> * check if it is connected to HW that can do Offload at all
>>> * check if Offload streams are available on backing HW
>>> * check if audio formats are supported by above HW
>>> * do any other checks that may be needed
>>> and then just redirect FE setup to relevant driver doing offload if
>>> able, otherwise just go standard path.
>>
>> How would userspace know which 'USB FE' to use?
>>
>
> That's my point, the same one as it would use doing normal playback/capture on systems which don't have Offload.
>
> If I attach USB Headphones, as a user my expectation would be to use playback FE on USB card it exposes, not to spend time setting some controls and telling it to use some FE from other card.
>
IMO I think the user should have the ability to choose whether or not to enable the offload path, since there are a lot of different USB audio devices in the market.  Obviously, the audio DSP will try its best to support every device we check for, but there might be a few outliers that may behave differently.  In addition, the code complexity that would be involved in bridging the PCM device exposed by USB SND into ASoC will be much more invasive to SND core code.  At least as of now, if the offload code is added, and userspace doesn't know anything about it, then the default USB SND path is taken and that won't break any current userspace applications.

Now, if we go and add some kernel based offload routing, and forcing that onto every userspace application, and we break that use case, that would be a problem.  In the end, I think if userspace wants to enable offloading they should need to have some changes implemented to account for it.  In discussions with Pierre, maybe enabling the offload path can be on a policy based condition, such as a "low power/power aware" audio path, and not something that is always enabled.

Thanks

Wesley Cheng

> With current design there are _two_ separate FEs, on _two_ separate cards, which are linked by kcontrol and which block each other. I'm rather confused how basic userspace application knows which one to use in this case. (By now of course I know that it needs to read kcontrol to see if and where it is offloaded and then open the FE on the card, but in my opinion it is unnecessarily convoluted.)
>
>> The discovery and mapping between cards and devices is the main problem.
>>
>
> And "offloading" decision to the user/sound server/HAL doesn't help in my opinion.
>
>> It's much simpler to start from a generic "USB-Audio" card, and check if
>> the functionality exposed by one PCM device is offloaded to another
>> ASoC-based card. Then all the interaction can start with this offloaded
>> device without any guesswork on the mapping between cards/devices.
>>
>
> That's the point, currently there needs to be some guesswork involved, because you need to check kcontrols to see if the endpoint can be offloaded and open the other FE it points at, instead of directly opening the one you usually would, and having it Offloaded by kernel. It is adding more work on userspace side, which will require special handling to work correctly.
>
>> The point is that the USB-Audio card will always be there, whereas those
>> ASoC cards will have different names and implementation restrictions. In
>> the example we have here, if you want to capture audio you *have* to use
>> the USB-Audio card.
>>
>
> Yes and with the description above it would be just one of the checks after which it would decide that it can't do Offload on capture path and open it in standard way, I see no problem?
>
>> In other words, it's just an endianness type of debate with no clear
>> difference between solutions and a matter of personal preference. The
>> reality is that there's a clear asymmetrical pattern. The USB-Audio card
>> is always present and usable, the ASoC offloaded cards are only present
>> in specific implementations and only usable if conditions are met.
>
> In my opinion even if it is specific use case, there is no reason to make it more complicated than it needs to be. From my point of view problem with current design is that instead of being mostly transparent to userspace (when it could be), it adds more work for it.
>
diff mbox series

Patch

diff --git a/sound/usb/card.h b/sound/usb/card.h
index 02e4ea898db5..e98883785301 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -165,6 +165,7 @@  struct snd_usb_substream {
 	unsigned int pkt_offset_adj;	/* Bytes to drop from beginning of packets (for non-compliant devices) */
 	unsigned int stream_offset_adj;	/* Bytes to drop from beginning of stream (for non-compliant devices) */
 
+	unsigned int opened:1;		/* pcm device opened */
 	unsigned int running: 1;	/* running status */
 	unsigned int period_elapsed_pending;	/* delay period handling */
 
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 3adb09ce1702..3e6d33de6ce6 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -1241,8 +1241,17 @@  static int snd_usb_pcm_open(struct snd_pcm_substream *substream)
 	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];
+	struct snd_usb_audio *chip = subs->stream->chip;
 	int ret;
 
+	mutex_lock(&chip->mutex);
+	if (subs->opened) {
+		mutex_unlock(&chip->mutex);
+		return -EBUSY;
+	}
+	subs->opened = 1;
+	mutex_unlock(&chip->mutex);
+
 	runtime->hw = snd_usb_hardware;
 	/* need an explicit sync to catch applptr update in low-latency mode */
 	if (direction == SNDRV_PCM_STREAM_PLAYBACK &&
@@ -1259,13 +1268,23 @@  static int snd_usb_pcm_open(struct snd_pcm_substream *substream)
 
 	ret = setup_hw_info(runtime, subs);
 	if (ret < 0)
-		return ret;
+		goto err_open;
 	ret = snd_usb_autoresume(subs->stream->chip);
 	if (ret < 0)
-		return ret;
+		goto err_open;
 	ret = snd_media_stream_init(subs, as->pcm, direction);
 	if (ret < 0)
-		snd_usb_autosuspend(subs->stream->chip);
+		goto err_resume;
+
+	return 0;
+
+err_resume:
+	snd_usb_autosuspend(subs->stream->chip);
+err_open:
+	mutex_lock(&chip->mutex);
+	subs->opened = 0;
+	mutex_unlock(&chip->mutex);
+
 	return ret;
 }
 
@@ -1274,6 +1293,7 @@  static int snd_usb_pcm_close(struct snd_pcm_substream *substream)
 	int direction = substream->stream;
 	struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
 	struct snd_usb_substream *subs = &as->substream[direction];
+	struct snd_usb_audio *chip = subs->stream->chip;
 	int ret;
 
 	snd_media_stop_pipeline(subs);
@@ -1287,6 +1307,9 @@  static int snd_usb_pcm_close(struct snd_pcm_substream *substream)
 
 	subs->pcm_substream = NULL;
 	snd_usb_autosuspend(subs->stream->chip);
+	mutex_lock(&chip->mutex);
+	subs->opened = 0;
+	mutex_unlock(&chip->mutex);
 
 	return 0;
 }