Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3179f620 authored by Pierre-Louis Bossart's avatar Pierre-Louis Bossart Committed by Takashi Iwai
Browse files

ALSA: core: add .get_time_info



Introduce more generic .get_time_info to retrieve
system timestamp and audio timestamp in single routine.
Backwards compatibility is preserved with same functionality
as with .wall_clock method (to be removed in following commits
to avoid breaking git bisect)

Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 5442a73a
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -76,6 +76,10 @@ struct snd_pcm_ops {
	snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream);
	snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream);
	int (*wall_clock)(struct snd_pcm_substream *substream,
	int (*wall_clock)(struct snd_pcm_substream *substream,
			  struct timespec *audio_ts);
			  struct timespec *audio_ts);
	int (*get_time_info)(struct snd_pcm_substream *substream,
			struct timespec *system_ts, struct timespec *audio_ts,
			struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
			struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
	int (*copy)(struct snd_pcm_substream *substream, int channel,
	int (*copy)(struct snd_pcm_substream *substream, int channel,
		    snd_pcm_uframes_t pos,
		    snd_pcm_uframes_t pos,
		    void __user *buf, snd_pcm_uframes_t count);
		    void __user *buf, snd_pcm_uframes_t count);
+59 −29
Original line number Original line Diff line number Diff line
@@ -232,6 +232,49 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream,
	return 0;
	return 0;
}
}


static void update_audio_tstamp(struct snd_pcm_substream *substream,
				struct timespec *curr_tstamp,
				struct timespec *audio_tstamp)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	u64 audio_frames, audio_nsecs;
	struct timespec driver_tstamp;

	if (runtime->tstamp_mode != SNDRV_PCM_TSTAMP_ENABLE)
		return;

	if (!(substream->ops->get_time_info) ||
		(runtime->audio_tstamp_report.actual_type ==
			SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) {

		/*
		 * provide audio timestamp derived from pointer position
		 * add delay only if requested
		 */

		audio_frames = runtime->hw_ptr_wrap + runtime->status->hw_ptr;

		if (runtime->audio_tstamp_config.report_delay) {
			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
				audio_frames -=  runtime->delay;
			else
				audio_frames +=  runtime->delay;
		}
		audio_nsecs = div_u64(audio_frames * 1000000000LL,
				runtime->rate);
		*audio_tstamp = ns_to_timespec(audio_nsecs);
	}
	runtime->status->audio_tstamp = *audio_tstamp;
	runtime->status->tstamp = *curr_tstamp;

	/*
	 * re-take a driver timestamp to let apps detect if the reference tstamp
	 * read by low-level hardware was provided with a delay
	 */
	snd_pcm_gettime(substream->runtime, (struct timespec *)&driver_tstamp);
	runtime->driver_tstamp = driver_tstamp;
}

static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
				  unsigned int in_interrupt)
				  unsigned int in_interrupt)
{
{
@@ -256,11 +299,18 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
	pos = substream->ops->pointer(substream);
	pos = substream->ops->pointer(substream);
	curr_jiffies = jiffies;
	curr_jiffies = jiffies;
	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
		if ((substream->ops->get_time_info) &&
			(runtime->audio_tstamp_config.type_requested != SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) {
			substream->ops->get_time_info(substream, &curr_tstamp,
						&audio_tstamp,
						&runtime->audio_tstamp_config,
						&runtime->audio_tstamp_report);

			/* re-test in case tstamp type is not supported in hardware and was demoted to DEFAULT */
			if (runtime->audio_tstamp_report.actual_type == SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)
				snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
		} else
			snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
			snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);

		if ((runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) &&
			(substream->ops->wall_clock))
			substream->ops->wall_clock(substream, &audio_tstamp);
	}
	}


	if (pos == SNDRV_PCM_POS_XRUN) {
	if (pos == SNDRV_PCM_POS_XRUN) {
@@ -403,8 +453,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
	}
	}


 no_delta_check:
 no_delta_check:
	if (runtime->status->hw_ptr == new_hw_ptr)
	if (runtime->status->hw_ptr == new_hw_ptr) {
		update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp);
		return 0;
		return 0;
	}


	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
	    runtime->silence_size > 0)
	    runtime->silence_size > 0)
@@ -426,30 +478,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
		snd_BUG_ON(crossed_boundary != 1);
		snd_BUG_ON(crossed_boundary != 1);
		runtime->hw_ptr_wrap += runtime->boundary;
		runtime->hw_ptr_wrap += runtime->boundary;
	}
	}
	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
		runtime->status->tstamp = curr_tstamp;

		if (!(runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)) {
			/*
			 * no wall clock available, provide audio timestamp
			 * derived from pointer position+delay
			 */
			u64 audio_frames, audio_nsecs;


			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
	update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp);
				audio_frames = runtime->hw_ptr_wrap
					+ runtime->status->hw_ptr
					- runtime->delay;
			else
				audio_frames = runtime->hw_ptr_wrap
					+ runtime->status->hw_ptr
					+ runtime->delay;
			audio_nsecs = div_u64(audio_frames * 1000000000LL,
					runtime->rate);
			audio_tstamp = ns_to_timespec(audio_nsecs);
		}
		runtime->status->audio_tstamp = audio_tstamp;
	}


	return snd_pcm_update_state(substream, runtime);
	return snd_pcm_update_state(substream, runtime);
}
}
+24 −0
Original line number Original line Diff line number Diff line
@@ -707,6 +707,23 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_pcm_runtime *runtime = substream->runtime;


	snd_pcm_stream_lock_irq(substream);
	snd_pcm_stream_lock_irq(substream);

	snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data,
					&runtime->audio_tstamp_config);

	/* backwards compatible behavior */
	if (runtime->audio_tstamp_config.type_requested ==
		SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT) {
		if (runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)
			runtime->audio_tstamp_config.type_requested =
				SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK;
		else
			runtime->audio_tstamp_config.type_requested =
				SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT;
		runtime->audio_tstamp_report.valid = 0;
	} else
		runtime->audio_tstamp_report.valid = 1;

	status->state = runtime->status->state;
	status->state = runtime->status->state;
	status->suspended_state = runtime->status->suspended_state;
	status->suspended_state = runtime->status->suspended_state;
	if (status->state == SNDRV_PCM_STATE_OPEN)
	if (status->state == SNDRV_PCM_STATE_OPEN)
@@ -716,8 +733,15 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
		snd_pcm_update_hw_ptr(substream);
		snd_pcm_update_hw_ptr(substream);
		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
			status->tstamp = runtime->status->tstamp;
			status->tstamp = runtime->status->tstamp;
			status->driver_tstamp = runtime->driver_tstamp;
			status->audio_tstamp =
			status->audio_tstamp =
				runtime->status->audio_tstamp;
				runtime->status->audio_tstamp;
			if (runtime->audio_tstamp_report.valid == 1)
				/* backwards compatibility, no report provided in COMPAT mode */
				snd_pcm_pack_audio_tstamp_report(&status->audio_tstamp_data,
								&status->audio_tstamp_accuracy,
								&runtime->audio_tstamp_report);

			goto _tstamp_end;
			goto _tstamp_end;
		}
		}
	} else {
	} else {