aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/pcm_lib.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-03-23 08:14:02 -0400
committerTakashi Iwai <tiwai@suse.de>2015-03-23 08:14:02 -0400
commit3372dbdd8ca11f51be8c6a30b2bc79eb04c4a902 (patch)
treed4499bf5a5665b4820ffaf96bce55bf6b895195e /sound/core/pcm_lib.c
parentbc465aa9d045feb0e13b4a8f32cc33c1943f62d6 (diff)
parent967b1307b69b8ada8b331e01046ad1ef83742e99 (diff)
Merge branch 'for-next' into topic/hda-core
Diffstat (limited to 'sound/core/pcm_lib.c')
-rw-r--r--sound/core/pcm_lib.c88
1 files changed, 59 insertions, 29 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index ffd656012ab8..ac6b33f3779c 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,
232 return 0; 232 return 0;
233} 233}
234 234
235static void update_audio_tstamp(struct snd_pcm_substream *substream,
236 struct timespec *curr_tstamp,
237 struct timespec *audio_tstamp)
238{
239 struct snd_pcm_runtime *runtime = substream->runtime;
240 u64 audio_frames, audio_nsecs;
241 struct timespec driver_tstamp;
242
243 if (runtime->tstamp_mode != SNDRV_PCM_TSTAMP_ENABLE)
244 return;
245
246 if (!(substream->ops->get_time_info) ||
247 (runtime->audio_tstamp_report.actual_type ==
248 SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) {
249
250 /*
251 * provide audio timestamp derived from pointer position
252 * add delay only if requested
253 */
254
255 audio_frames = runtime->hw_ptr_wrap + runtime->status->hw_ptr;
256
257 if (runtime->audio_tstamp_config.report_delay) {
258 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
259 audio_frames -= runtime->delay;
260 else
261 audio_frames += runtime->delay;
262 }
263 audio_nsecs = div_u64(audio_frames * 1000000000LL,
264 runtime->rate);
265 *audio_tstamp = ns_to_timespec(audio_nsecs);
266 }
267 runtime->status->audio_tstamp = *audio_tstamp;
268 runtime->status->tstamp = *curr_tstamp;
269
270 /*
271 * re-take a driver timestamp to let apps detect if the reference tstamp
272 * read by low-level hardware was provided with a delay
273 */
274 snd_pcm_gettime(substream->runtime, (struct timespec *)&driver_tstamp);
275 runtime->driver_tstamp = driver_tstamp;
276}
277
235static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, 278static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
236 unsigned int in_interrupt) 279 unsigned int in_interrupt)
237{ 280{
@@ -256,11 +299,18 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
256 pos = substream->ops->pointer(substream); 299 pos = substream->ops->pointer(substream);
257 curr_jiffies = jiffies; 300 curr_jiffies = jiffies;
258 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { 301 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
259 snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); 302 if ((substream->ops->get_time_info) &&
260 303 (runtime->audio_tstamp_config.type_requested != SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) {
261 if ((runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) && 304 substream->ops->get_time_info(substream, &curr_tstamp,
262 (substream->ops->wall_clock)) 305 &audio_tstamp,
263 substream->ops->wall_clock(substream, &audio_tstamp); 306 &runtime->audio_tstamp_config,
307 &runtime->audio_tstamp_report);
308
309 /* re-test in case tstamp type is not supported in hardware and was demoted to DEFAULT */
310 if (runtime->audio_tstamp_report.actual_type == SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)
311 snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
312 } else
313 snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
264 } 314 }
265 315
266 if (pos == SNDRV_PCM_POS_XRUN) { 316 if (pos == SNDRV_PCM_POS_XRUN) {
@@ -403,8 +453,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
403 } 453 }
404 454
405 no_delta_check: 455 no_delta_check:
406 if (runtime->status->hw_ptr == new_hw_ptr) 456 if (runtime->status->hw_ptr == new_hw_ptr) {
457 update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp);
407 return 0; 458 return 0;
459 }
408 460
409 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && 461 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
410 runtime->silence_size > 0) 462 runtime->silence_size > 0)
@@ -426,30 +478,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
426 snd_BUG_ON(crossed_boundary != 1); 478 snd_BUG_ON(crossed_boundary != 1);
427 runtime->hw_ptr_wrap += runtime->boundary; 479 runtime->hw_ptr_wrap += runtime->boundary;
428 } 480 }
429 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
430 runtime->status->tstamp = curr_tstamp;
431 481
432 if (!(runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)) { 482 update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp);
433 /*
434 * no wall clock available, provide audio timestamp
435 * derived from pointer position+delay
436 */
437 u64 audio_frames, audio_nsecs;
438
439 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
440 audio_frames = runtime->hw_ptr_wrap
441 + runtime->status->hw_ptr
442 - runtime->delay;
443 else
444 audio_frames = runtime->hw_ptr_wrap
445 + runtime->status->hw_ptr
446 + runtime->delay;
447 audio_nsecs = div_u64(audio_frames * 1000000000LL,
448 runtime->rate);
449 audio_tstamp = ns_to_timespec(audio_nsecs);
450 }
451 runtime->status->audio_tstamp = audio_tstamp;
452 }
453 483
454 return snd_pcm_update_state(substream, runtime); 484 return snd_pcm_update_state(substream, runtime);
455} 485}