diff options
Diffstat (limited to 'sound')
-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; |