[alsa-devel] [PATCH v6 4/7] ALSA: core: add .get_time_info
Pierre-Louis Bossart
pierre-louis.bossart at linux.intel.com
Fri Feb 13 22:14:06 CET 2015
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: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
---
include/sound/pcm.h | 4 +++
sound/core/pcm_lib.c | 88 +++++++++++++++++++++++++++++++++----------------
sound/core/pcm_native.c | 24 ++++++++++++++
3 files changed, 87 insertions(+), 29 deletions(-)
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 60f0e48..04f2d49 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -76,6 +76,10 @@ struct snd_pcm_ops {
snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream);
int (*wall_clock)(struct snd_pcm_substream *substream,
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,
snd_pcm_uframes_t pos,
void __user *buf, snd_pcm_uframes_t count);
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index ffd6560..ac6b33f 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -232,6 +232,49 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream,
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,
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);
curr_jiffies = jiffies;
if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
- 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 ((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);
}
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:
- 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;
+ }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
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);
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)
- 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;
- }
+ update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp);
return snd_pcm_update_state(substream, runtime);
}
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 72323a8..9c2c6f8 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -707,6 +707,23 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
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->suspended_state = runtime->status->suspended_state;
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);
if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
status->tstamp = runtime->status->tstamp;
+ status->driver_tstamp = runtime->driver_tstamp;
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;
}
} else {
--
1.9.1
More information about the Alsa-devel
mailing list