aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core
diff options
context:
space:
mode:
authorJeeja KP <jeeja.kp@intel.com>2013-02-14 06:22:51 -0500
committerTakashi Iwai <tiwai@suse.de>2013-02-14 06:30:22 -0500
commit9727b490e543de956b8ba356e2d5499097d0b7a2 (patch)
tree81c41ee5b9987fdcb32c474484c39f45210507c0 /sound/core
parent8be69efacdc73fc110624f847bdf04b83decfc70 (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.c96
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
522static int
523snd_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
544static int
545snd_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
520static inline int 565static inline int
521snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg) 566snd_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
648static 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
670static 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
603static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) 686static 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;