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: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Pierre-Louis Bossart 2015-02-13 15:14:06 -06:00 committed by Takashi Iwai
parent 5442a73a00
commit 3179f62001
3 changed files with 86 additions and 28 deletions

View File

@ -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);

View File

@ -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 ((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);
if ((runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) &&
(substream->ops->wall_clock))
substream->ops->wall_clock(substream, &audio_tstamp);
/* 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);
}

View File

@ -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 {