diff options
author | Jeeja KP <jeeja.kp@intel.com> | 2013-02-14 06:22:51 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-02-14 06:30:22 -0500 |
commit | 9727b490e543de956b8ba356e2d5499097d0b7a2 (patch) | |
tree | 81c41ee5b9987fdcb32c474484c39f45210507c0 /sound/core | |
parent | 8be69efacdc73fc110624f847bdf04b83decfc70 (diff) |
ALSA: compress: add support for gapless playback
this add new API for sound compress to support gapless playback.
As noted in Documentation change, we add API to send metadata of encoder and
padding delay to DSP. Also add API for indicating EOF and switching to
subsequent track
Also bump the compress API version
Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core')
-rw-r--r-- | sound/core/compress_offload.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 2d620688cfb7..c84abc886e90 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c | |||
@@ -486,6 +486,8 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg) | |||
486 | if (retval) | 486 | if (retval) |
487 | goto out; | 487 | goto out; |
488 | stream->runtime->state = SNDRV_PCM_STATE_SETUP; | 488 | stream->runtime->state = SNDRV_PCM_STATE_SETUP; |
489 | stream->metadata_set = false; | ||
490 | stream->next_track = false; | ||
489 | } else { | 491 | } else { |
490 | return -EPERM; | 492 | return -EPERM; |
491 | } | 493 | } |
@@ -517,6 +519,49 @@ out: | |||
517 | return retval; | 519 | return retval; |
518 | } | 520 | } |
519 | 521 | ||
522 | static int | ||
523 | snd_compr_get_metadata(struct snd_compr_stream *stream, unsigned long arg) | ||
524 | { | ||
525 | struct snd_compr_metadata metadata; | ||
526 | int retval; | ||
527 | |||
528 | if (!stream->ops->get_metadata) | ||
529 | return -ENXIO; | ||
530 | |||
531 | if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata))) | ||
532 | return -EFAULT; | ||
533 | |||
534 | retval = stream->ops->get_metadata(stream, &metadata); | ||
535 | if (retval != 0) | ||
536 | return retval; | ||
537 | |||
538 | if (copy_to_user((void __user *)arg, &metadata, sizeof(metadata))) | ||
539 | return -EFAULT; | ||
540 | |||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | static int | ||
545 | snd_compr_set_metadata(struct snd_compr_stream *stream, unsigned long arg) | ||
546 | { | ||
547 | struct snd_compr_metadata metadata; | ||
548 | int retval; | ||
549 | |||
550 | if (!stream->ops->set_metadata) | ||
551 | return -ENXIO; | ||
552 | /* | ||
553 | * we should allow parameter change only when stream has been | ||
554 | * opened not in other cases | ||
555 | */ | ||
556 | if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata))) | ||
557 | return -EFAULT; | ||
558 | |||
559 | retval = stream->ops->set_metadata(stream, &metadata); | ||
560 | stream->metadata_set = true; | ||
561 | |||
562 | return retval; | ||
563 | } | ||
564 | |||
520 | static inline int | 565 | static inline int |
521 | snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg) | 566 | snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg) |
522 | { | 567 | { |
@@ -600,6 +645,44 @@ static int snd_compr_drain(struct snd_compr_stream *stream) | |||
600 | return retval; | 645 | return retval; |
601 | } | 646 | } |
602 | 647 | ||
648 | static int snd_compr_next_track(struct snd_compr_stream *stream) | ||
649 | { | ||
650 | int retval; | ||
651 | |||
652 | /* only a running stream can transition to next track */ | ||
653 | if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING) | ||
654 | return -EPERM; | ||
655 | |||
656 | /* you can signal next track isf this is intended to be a gapless stream | ||
657 | * and current track metadata is set | ||
658 | */ | ||
659 | if (stream->metadata_set == false) | ||
660 | return -EPERM; | ||
661 | |||
662 | retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_NEXT_TRACK); | ||
663 | if (retval != 0) | ||
664 | return retval; | ||
665 | stream->metadata_set = false; | ||
666 | stream->next_track = true; | ||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | static int snd_compr_partial_drain(struct snd_compr_stream *stream) | ||
671 | { | ||
672 | int retval; | ||
673 | if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED || | ||
674 | stream->runtime->state == SNDRV_PCM_STATE_SETUP) | ||
675 | return -EPERM; | ||
676 | /* stream can be drained only when next track has been signalled */ | ||
677 | if (stream->next_track == false) | ||
678 | return -EPERM; | ||
679 | |||
680 | retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN); | ||
681 | |||
682 | stream->next_track = false; | ||
683 | return retval; | ||
684 | } | ||
685 | |||
603 | static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | 686 | static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) |
604 | { | 687 | { |
605 | struct snd_compr_file *data = f->private_data; | 688 | struct snd_compr_file *data = f->private_data; |
@@ -629,6 +712,12 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | |||
629 | case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS): | 712 | case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS): |
630 | retval = snd_compr_get_params(stream, arg); | 713 | retval = snd_compr_get_params(stream, arg); |
631 | break; | 714 | break; |
715 | case _IOC_NR(SNDRV_COMPRESS_SET_METADATA): | ||
716 | retval = snd_compr_set_metadata(stream, arg); | ||
717 | break; | ||
718 | case _IOC_NR(SNDRV_COMPRESS_GET_METADATA): | ||
719 | retval = snd_compr_get_metadata(stream, arg); | ||
720 | break; | ||
632 | case _IOC_NR(SNDRV_COMPRESS_TSTAMP): | 721 | case _IOC_NR(SNDRV_COMPRESS_TSTAMP): |
633 | retval = snd_compr_tstamp(stream, arg); | 722 | retval = snd_compr_tstamp(stream, arg); |
634 | break; | 723 | break; |
@@ -650,6 +739,13 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | |||
650 | case _IOC_NR(SNDRV_COMPRESS_DRAIN): | 739 | case _IOC_NR(SNDRV_COMPRESS_DRAIN): |
651 | retval = snd_compr_drain(stream); | 740 | retval = snd_compr_drain(stream); |
652 | break; | 741 | break; |
742 | case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN): | ||
743 | retval = snd_compr_partial_drain(stream); | ||
744 | break; | ||
745 | case _IOC_NR(SNDRV_COMPRESS_NEXT_TRACK): | ||
746 | retval = snd_compr_next_track(stream); | ||
747 | break; | ||
748 | |||
653 | } | 749 | } |
654 | mutex_unlock(&stream->device->lock); | 750 | mutex_unlock(&stream->device->lock); |
655 | return retval; | 751 | return retval; |