Skip to content

Commit cdac6e1

Browse files
Chancel Liutiwai
authored andcommitted
ALSA: aloop: Introduce a function to get if access is interleaved mode
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: 4624945 ("ALSA: aloop: Add support for the non-interleaved access mode") Signed-off-by: Chancel Liu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent fd38dd6 commit cdac6e1

File tree

1 file changed

+17
-6
lines changed

1 file changed

+17
-6
lines changed

sound/drivers/aloop.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,17 @@ static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm)
322322
return 0;
323323
}
324324

325+
static bool is_access_interleaved(snd_pcm_access_t access)
326+
{
327+
switch (access) {
328+
case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:
329+
case SNDRV_PCM_ACCESS_RW_INTERLEAVED:
330+
return true;
331+
default:
332+
return false;
333+
}
334+
};
335+
325336
static int loopback_check_format(struct loopback_cable *cable, int stream)
326337
{
327338
struct snd_pcm_runtime *runtime, *cruntime;
@@ -341,7 +352,8 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
341352
check = runtime->format != cruntime->format ||
342353
runtime->rate != cruntime->rate ||
343354
runtime->channels != cruntime->channels ||
344-
runtime->access != cruntime->access;
355+
is_access_interleaved(runtime->access) !=
356+
is_access_interleaved(cruntime->access);
345357
if (!check)
346358
return 0;
347359
if (stream == SNDRV_PCM_STREAM_CAPTURE) {
@@ -369,7 +381,8 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
369381
&setup->channels_id);
370382
setup->channels = runtime->channels;
371383
}
372-
if (setup->access != runtime->access) {
384+
if (is_access_interleaved(setup->access) !=
385+
is_access_interleaved(runtime->access)) {
373386
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
374387
&setup->access_id);
375388
setup->access = runtime->access;
@@ -584,8 +597,7 @@ static void copy_play_buf(struct loopback_pcm *play,
584597
size = play->pcm_buffer_size - src_off;
585598
if (dst_off + size > capt->pcm_buffer_size)
586599
size = capt->pcm_buffer_size - dst_off;
587-
if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ||
588-
runtime->access == SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED)
600+
if (!is_access_interleaved(runtime->access))
589601
copy_play_buf_part_n(play, capt, size, src_off, dst_off);
590602
else
591603
memcpy(dst + dst_off, src + src_off, size);
@@ -1544,8 +1556,7 @@ static int loopback_access_get(struct snd_kcontrol *kcontrol,
15441556
mutex_lock(&loopback->cable_lock);
15451557
access = loopback->setup[kcontrol->id.subdevice][kcontrol->id.device].access;
15461558

1547-
ucontrol->value.enumerated.item[0] = access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ||
1548-
access == SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED;
1559+
ucontrol->value.enumerated.item[0] = !is_access_interleaved(access);
15491560

15501561
mutex_unlock(&loopback->cable_lock);
15511562
return 0;

0 commit comments

Comments
 (0)