Commit 22459ef3 authored by Ivan Orlov's avatar Ivan Orlov Committed by Takashi Iwai
Browse files

ALSA: pcmtest: Add support for pcm pausing



Add pause push/release support to the virtual PCM test driver. Add
'suspend' boolean field to the pcmtst_buf_iter structure, so we can
pause the timer without shutting it down. Update the trigger callback
handler correspondingly. Extract buffer initialization to the
'reset_buf_iterator' function since it is used in multiple places now.

Signed-off-by: default avatarIvan Orlov <ivan.orlov0322@gmail.com>
Link: https://lore.kernel.org/r/20230822150541.8450-1-ivan.orlov0322@gmail.com


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 93dc18e1
Loading
Loading
Loading
Loading
+41 −8
Original line number Diff line number Diff line
@@ -108,6 +108,7 @@ struct pcmtst_buf_iter {
	size_t total_bytes;			// Total bytes read/written
	size_t chan_block;			// Bytes in one channel buffer when non-interleaved
	struct snd_pcm_substream *substream;
	bool suspend;				// We need to pause timer without shutting it down
	struct timer_list timer_instance;
};

@@ -115,7 +116,8 @@ static struct snd_pcm_hardware snd_pcmtst_hw = {
	.info = (SNDRV_PCM_INFO_INTERLEAVED |
		 SNDRV_PCM_INFO_BLOCK_TRANSFER |
		 SNDRV_PCM_INFO_NONINTERLEAVED |
		 SNDRV_PCM_INFO_MMAP_VALID),
		 SNDRV_PCM_INFO_MMAP_VALID |
		 SNDRV_PCM_INFO_PAUSE),
	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
	.rates =		SNDRV_PCM_RATE_8000_48000,
	.rate_min =		8000,
@@ -346,6 +348,9 @@ static void timer_timeout(struct timer_list *data)
	v_iter = from_timer(v_iter, data, timer_instance);
	substream = v_iter->substream;

	if (v_iter->suspend)
		return;

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !v_iter->is_buf_corrupted)
		check_buf_block(v_iter, substream->runtime);
	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
@@ -358,6 +363,8 @@ static void timer_timeout(struct timer_list *data)
		v_iter->period_pos %= v_iter->period_bytes;
		snd_pcm_period_elapsed(substream);
	}

	if (!v_iter->suspend)
		mod_timer(&v_iter->timer_instance, jiffies + TIMER_INTERVAL + inject_delay);
}

@@ -373,19 +380,15 @@ static int snd_pcmtst_pcm_open(struct snd_pcm_substream *substream)
	if (!v_iter)
		return -ENOMEM;

	v_iter->substream = substream;
	runtime->hw = snd_pcmtst_hw;
	runtime->private_data = v_iter;
	v_iter->substream = substream;
	v_iter->buf_pos = 0;
	v_iter->is_buf_corrupted = false;
	v_iter->period_pos = 0;
	v_iter->total_bytes = 0;

	playback_capture_test = 0;
	ioctl_reset_test = 0;

	timer_setup(&v_iter->timer_instance, timer_timeout, 0);
	mod_timer(&v_iter->timer_instance, jiffies + TIMER_INTERVAL);

	return 0;
}

@@ -400,10 +403,40 @@ static int snd_pcmtst_pcm_close(struct snd_pcm_substream *substream)
	return 0;
}

static inline void reset_buf_iterator(struct pcmtst_buf_iter *v_iter)
{
	v_iter->buf_pos = 0;
	v_iter->is_buf_corrupted = false;
	v_iter->period_pos = 0;
	v_iter->total_bytes = 0;
}

static inline void start_pcmtest_timer(struct pcmtst_buf_iter *v_iter)
{
	v_iter->suspend = false;
	mod_timer(&v_iter->timer_instance, jiffies + TIMER_INTERVAL);
}

static int snd_pcmtst_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
	struct pcmtst_buf_iter *v_iter = substream->runtime->private_data;

	if (inject_trigger_err)
		return -EINVAL;
	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
		reset_buf_iterator(v_iter);
		start_pcmtest_timer(v_iter);
		break;
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		start_pcmtest_timer(v_iter);
		break;
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		// We can't call timer_shutdown_sync here, as it is forbidden to sleep here
		v_iter->suspend = true;
		break;
	}

	return 0;
}