diff mbox series

ALSA: aloop: Introduce a function to get if access is interleaved mode

Message ID 20240111025219.2678764-1-chancel.liu@nxp.com (mailing list archive)
State Accepted
Commit cdac6e1f716419ce307ad3e44a718557a5469c17
Headers show
Series ALSA: aloop: Introduce a function to get if access is interleaved mode | expand

Commit Message

Chancel Liu Jan. 11, 2024, 2:52 a.m. UTC
There's a use case that playback stream of a loopback cable works on
RW_INTERLEAVED mode while capture stream works on MMAP_INTERLEAVED mode:

aplay -Dhw:Loopback,0,0 S32_48K_2ch.wav;
arecord -Dplughw:Loopback,1,0 -fS32_LE -r16000 -c2 cap.wav;

The plug plugin handles only slave PCM support MMAP mode. Not only plug
plugin but also other plugins like direct plugins(dmix/dsnoop/dshare)
work on MMAP access mode. In this case capture stream is the slave
PCM works on MMAP_INTERLEAVED mode. However loopback_check_format()
rejects this access setting and return:

arecord: pcm_read:2240: read error: Input/output error

To fix it a function called is_access_interleaved() is introduced to
get if access is interleaved mode. If both access of capture stream and
playback stream is interleaved mode loopback_check_format() will allow
this kind of access setting.

Fixes: 462494565c27 ("ALSA: aloop: Add support for the non-interleaved access mode")
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
 sound/drivers/aloop.c | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

Comments

Takashi Iwai Jan. 12, 2024, 8:46 a.m. UTC | #1
On Thu, 11 Jan 2024 03:52:19 +0100,
Chancel Liu wrote:
> 
> There's a use case that playback stream of a loopback cable works on
> RW_INTERLEAVED mode while capture stream works on MMAP_INTERLEAVED mode:
> 
> aplay -Dhw:Loopback,0,0 S32_48K_2ch.wav;
> arecord -Dplughw:Loopback,1,0 -fS32_LE -r16000 -c2 cap.wav;
> 
> The plug plugin handles only slave PCM support MMAP mode. Not only plug
> plugin but also other plugins like direct plugins(dmix/dsnoop/dshare)
> work on MMAP access mode. In this case capture stream is the slave
> PCM works on MMAP_INTERLEAVED mode. However loopback_check_format()
> rejects this access setting and return:
> 
> arecord: pcm_read:2240: read error: Input/output error
> 
> To fix it a function called is_access_interleaved() is introduced to
> get if access is interleaved mode. If both access of capture stream and
> playback stream is interleaved mode loopback_check_format() will allow
> this kind of access setting.
> 
> Fixes: 462494565c27 ("ALSA: aloop: Add support for the non-interleaved access mode")
> Signed-off-by: Chancel Liu <chancel.liu@nxp.com>

Applied now.  Thanks.


Takashi
diff mbox series

Patch

diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index e87dc67f33c6..1c65e0a3b13c 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -322,6 +322,17 @@  static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm)
 	return 0;
 }
 
+static bool is_access_interleaved(snd_pcm_access_t access)
+{
+	switch (access) {
+	case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:
+	case SNDRV_PCM_ACCESS_RW_INTERLEAVED:
+		return true;
+	default:
+		return false;
+	}
+};
+
 static int loopback_check_format(struct loopback_cable *cable, int stream)
 {
 	struct snd_pcm_runtime *runtime, *cruntime;
@@ -341,7 +352,8 @@  static int loopback_check_format(struct loopback_cable *cable, int stream)
 	check = runtime->format != cruntime->format ||
 		runtime->rate != cruntime->rate ||
 		runtime->channels != cruntime->channels ||
-		runtime->access != cruntime->access;
+		is_access_interleaved(runtime->access) !=
+		is_access_interleaved(cruntime->access);
 	if (!check)
 		return 0;
 	if (stream == SNDRV_PCM_STREAM_CAPTURE) {
@@ -369,7 +381,8 @@  static int loopback_check_format(struct loopback_cable *cable, int stream)
 							&setup->channels_id);
 			setup->channels = runtime->channels;
 		}
-		if (setup->access != runtime->access) {
+		if (is_access_interleaved(setup->access) !=
+		    is_access_interleaved(runtime->access)) {
 			snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
 							&setup->access_id);
 			setup->access = runtime->access;
@@ -584,8 +597,7 @@  static void copy_play_buf(struct loopback_pcm *play,
 			size = play->pcm_buffer_size - src_off;
 		if (dst_off + size > capt->pcm_buffer_size)
 			size = capt->pcm_buffer_size - dst_off;
-		if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ||
-		    runtime->access == SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED)
+		if (!is_access_interleaved(runtime->access))
 			copy_play_buf_part_n(play, capt, size, src_off, dst_off);
 		else
 			memcpy(dst + dst_off, src + src_off, size);
@@ -1544,8 +1556,7 @@  static int loopback_access_get(struct snd_kcontrol *kcontrol,
 	mutex_lock(&loopback->cable_lock);
 	access = loopback->setup[kcontrol->id.subdevice][kcontrol->id.device].access;
 
-	ucontrol->value.enumerated.item[0] = access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ||
-					     access == SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED;
+	ucontrol->value.enumerated.item[0] = !is_access_interleaved(access);
 
 	mutex_unlock(&loopback->cable_lock);
 	return 0;