1c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent/*
2c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * BSD LICENSE
3c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent *
4c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * tinycompress library for compress audio offload in alsa
5c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * Copyright (c) 2011-2012, Intel Corporation
6c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * All rights reserved.
7c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent *
8c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * Author: Vinod Koul <vinod.koul@linux.intel.com>
9c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent *
10c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * Redistribution and use in source and binary forms, with or without
11c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * modification, are permitted provided that the following conditions are met:
12c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent *
13c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * Redistributions of source code must retain the above copyright notice,
14c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * this list of conditions and the following disclaimer.
15c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * Redistributions in binary form must reproduce the above copyright notice,
16c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * this list of conditions and the following disclaimer in the documentation
17c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * and/or other materials provided with the distribution.
18c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * Neither the name of Intel Corporation nor the names of its contributors
19c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * may be used to endorse or promote products derived from this software
20c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * without specific prior written permission.
21c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent *
22c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * THE POSSIBILITY OF SUCH DAMAGE.
33c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent *
34c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * LGPL LICENSE
35c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent *
36c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * tinycompress library for compress audio offload in alsa
37c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * Copyright (c) 2011-2012, Intel Corporation.
38c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent *
39c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent *
40c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * This program is free software; you can redistribute it and/or modify it
41c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * under the terms and conditions of the GNU Lesser General Public License,
42c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * version 2.1, as published by the Free Software Foundation.
43c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent *
44c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * This program is distributed in the hope it will be useful, but WITHOUT
45c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
46c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
47c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * License for more details.
48c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent *
49c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * You should have received a copy of the GNU Lesser General Public License
50c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * along with this program; if not, write to
51c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * the Free Software Foundation, Inc.,
52c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
53c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent */
54c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
55c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <stdio.h>
56c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <stdlib.h>
57c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <fcntl.h>
58c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <stdarg.h>
59c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <string.h>
60c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <errno.h>
61c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <unistd.h>
62c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <poll.h>
63c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <stdbool.h>
64c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <sys/ioctl.h>
65c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <sys/mman.h>
66c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <sys/time.h>
67c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <limits.h>
68c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
69c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <linux/types.h>
70c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <linux/ioctl.h>
71c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#define __force
72c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#define __bitwise
73c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#define __user
74c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#include <sound/asound.h>
7579c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent#include "sound/compress_params.h"
7679c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent#include "sound/compress_offload.h"
7779c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent#include "tinycompress/tinycompress.h"
78c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
79c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#define COMPR_ERR_MAX 128
80c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
81c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent/* Default maximum time we will wait in a poll() - 20 seconds */
82c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#define DEFAULT_MAX_POLL_WAIT_MS    20000
83c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
84c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentstruct compress {
85c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	int fd;
86c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	unsigned int flags;
87c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	char error[COMPR_ERR_MAX];
88c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	struct compr_config *config;
89c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	int running;
90c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	int max_poll_wait_ms;
9179c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent	int nonblocking;
92c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	unsigned int gapless_metadata;
93c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	unsigned int next_track;
94c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent};
95c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
96c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentstatic int oops(struct compress *compress, int e, const char *fmt, ...)
97c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
98c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	va_list ap;
99c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	int sz;
100c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
101c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	va_start(ap, fmt);
102c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	vsnprintf(compress->error, COMPR_ERR_MAX, fmt, ap);
103c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	va_end(ap);
104c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	sz = strlen(compress->error);
105c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
10679c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent	snprintf(compress->error + sz, COMPR_ERR_MAX - sz,
10779c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		": %s", strerror(e));
10879c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent	errno = e;
10979c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent
11079c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent	return -1;
111c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
112c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
113c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentconst char *compress_get_error(struct compress *compress)
114c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
115c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return compress->error;
116c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
117c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentstatic struct compress bad_compress = {
118c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	.fd = -1,
119c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent};
120c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
121c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentint is_compress_running(struct compress *compress)
122c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
123c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return ((compress->fd > 0) && compress->running) ? 1 : 0;
124c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
125c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
126c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentint is_compress_ready(struct compress *compress)
127c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
128c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return (compress->fd > 0) ? 1 : 0;
129c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
130c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
131c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentstatic int get_compress_version(struct compress *compress)
132c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
133c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	int version = 0;
134c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
135c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (ioctl(compress->fd, SNDRV_COMPRESS_IOCTL_VERSION, &version)) {
136c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		oops(compress, errno, "cant read version");
137c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return -1;
138c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
139c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return version;
140c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
141c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
142c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentstatic bool _is_codec_supported(struct compress *compress, struct compr_config *config,
143c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent				const struct snd_compr_caps *caps)
144c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
145c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	bool codec = false;
146c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	unsigned int i;
147c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
148c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	for (i = 0; i < caps->num_codecs; i++) {
149c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		if (caps->codecs[i] == config->codec->id) {
150c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			/* found the codec */
151c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			codec = true;
152c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			break;
153c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		}
154c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
155c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (codec == false) {
15679c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		oops(compress, ENXIO, "this codec is not supported");
157c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return false;
158c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
159c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
160c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (config->fragment_size < caps->min_fragment_size) {
16179c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		oops(compress, EINVAL, "requested fragment size %d is below min supported %d",
162c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			config->fragment_size, caps->min_fragment_size);
163c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return false;
164c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
165c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (config->fragment_size > caps->max_fragment_size) {
16679c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		oops(compress, EINVAL, "requested fragment size %d is above max supported %d",
167c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			config->fragment_size, caps->max_fragment_size);
168c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return false;
169c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
170c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (config->fragments < caps->min_fragments) {
17179c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		oops(compress, EINVAL, "requested fragments %d are below min supported %d",
172c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			config->fragments, caps->min_fragments);
173c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return false;
174c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
175c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (config->fragments > caps->max_fragments) {
17679c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		oops(compress, EINVAL, "requested fragments %d are above max supported %d",
177c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			config->fragments, caps->max_fragments);
178c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return false;
179c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
180c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
181c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	/* TODO: match the codec properties */
182c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return true;
183c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
184c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
185c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentstatic bool _is_codec_type_supported(int fd, struct snd_codec *codec)
186c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
187c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	struct snd_compr_caps caps;
188c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	bool found = false;
189c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	unsigned int i;
190c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
191c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (ioctl(fd, SNDRV_COMPRESS_GET_CAPS, &caps)) {
192c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		oops(&bad_compress, errno, "cannot get device caps");
193c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return false;
194c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
195c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
196c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	for (i = 0; i < caps.num_codecs; i++) {
197c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		if (caps.codecs[i] == codec->id) {
198c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			/* found the codec */
199c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			found = true;
200c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			break;
201c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		}
202c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
203c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	/* TODO: match the codec properties */
204c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return found;
205c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
206c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
207c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentstatic inline void
208c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentfill_compress_params(struct compr_config *config, struct snd_compr_params *params)
209c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
210c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	params->buffer.fragment_size = config->fragment_size;
211c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	params->buffer.fragments = config->fragments;
212c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	memcpy(&params->codec, config->codec, sizeof(params->codec));
213c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
214c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
215c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentstruct compress *compress_open(unsigned int card, unsigned int device,
216c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		unsigned int flags, struct compr_config *config)
217c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
218c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	struct compress *compress;
219c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	struct snd_compr_params params;
220c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	struct snd_compr_caps caps;
221c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	char fn[256];
222c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
22379c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent	if (!config) {
22479c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		oops(&bad_compress, EINVAL, "passed bad config");
22579c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return &bad_compress;
22679c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent	}
22779c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent
228c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	compress = calloc(1, sizeof(struct compress));
22979c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent	if (!compress) {
230c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		oops(&bad_compress, errno, "cannot allocate compress object");
231c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return &bad_compress;
232c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
233c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
234c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	compress->next_track = 0;
235c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	compress->gapless_metadata = 0;
236c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	compress->config = calloc(1, sizeof(*config));
237c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (!compress->config)
238c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		goto input_fail;
239c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
240c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	snprintf(fn, sizeof(fn), "/dev/snd/comprC%uD%u", card, device);
241c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
242c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	compress->max_poll_wait_ms = DEFAULT_MAX_POLL_WAIT_MS;
243c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
244c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	compress->flags = flags;
245c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (!((flags & COMPRESS_OUT) || (flags & COMPRESS_IN))) {
24679c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		oops(&bad_compress, EINVAL, "can't deduce device direction from given flags");
247c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		goto config_fail;
248c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
249f0c407825741bcb94952e4264efce66dee378411Eric Laurent
250c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (flags & COMPRESS_OUT) {
251f0c407825741bcb94952e4264efce66dee378411Eric Laurent		compress->fd = open(fn, O_RDONLY);
252f0c407825741bcb94952e4264efce66dee378411Eric Laurent	} else {
253f0c407825741bcb94952e4264efce66dee378411Eric Laurent		compress->fd = open(fn, O_WRONLY);
254c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
255c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (compress->fd < 0) {
256c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		oops(&bad_compress, errno, "cannot open device '%s'", fn);
257c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		goto config_fail;
258c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
259c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
260c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (ioctl(compress->fd, SNDRV_COMPRESS_GET_CAPS, &caps)) {
261c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		oops(compress, errno, "cannot get device caps");
262c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		goto codec_fail;
263c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
264c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
265c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	/* If caller passed "don't care" fill in default values */
266c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if ((config->fragment_size == 0) || (config->fragments == 0)) {
267c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		config->fragment_size = caps.min_fragment_size;
268c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		config->fragments = caps.max_fragments;
269c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
270c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
271c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#if 0
272c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	/* FIXME need to turn this On when DSP supports
273c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	 * and treat in no support case
274c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	 */
275c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (_is_codec_supported(compress, config, &caps) == false) {
276c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		oops(compress, errno, "codec not supported\n");
277c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		goto codec_fail;
278c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
279c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent#endif
28079c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent
28179c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent	memcpy(compress->config, config, sizeof(*compress->config));
282c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	fill_compress_params(config, &params);
283c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
284c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (ioctl(compress->fd, SNDRV_COMPRESS_SET_PARAMS, &params)) {
285c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		oops(&bad_compress, errno, "cannot set device");
286c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		goto codec_fail;
287c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
288c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
289c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return compress;
290c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
291c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentcodec_fail:
292c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	close(compress->fd);
293c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	compress->fd = -1;
294c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentconfig_fail:
295c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	free(compress->config);
296c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentinput_fail:
297c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	free(compress);
298c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return &bad_compress;
299c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
300c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
301c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentvoid compress_close(struct compress *compress)
302c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
303c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (compress == &bad_compress)
304c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return;
305c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
306c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (compress->fd >= 0)
307c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		close(compress->fd);
308c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	compress->running = 0;
309c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	compress->fd = -1;
310c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	free(compress->config);
311c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	free(compress);
312c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
313c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
314c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentint compress_get_hpointer(struct compress *compress,
315c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		unsigned int *avail, struct timespec *tstamp)
316c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
317c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	struct snd_compr_avail kavail;
318c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	__u64 time;
319c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
320c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (!is_compress_ready(compress))
32179c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, ENODEV, "device not ready");
322c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
323c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (ioctl(compress->fd, SNDRV_COMPRESS_AVAIL, &kavail))
324c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return oops(compress, errno, "cannot get avail");
325c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (0 == kavail.tstamp.sampling_rate)
32679c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, ENODATA, "sample rate unknown");
327c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	*avail = (unsigned int)kavail.avail;
328c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	time = kavail.tstamp.pcm_io_frames / kavail.tstamp.sampling_rate;
329c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	tstamp->tv_sec = time;
330c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	time = kavail.tstamp.pcm_io_frames % kavail.tstamp.sampling_rate;
331c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	tstamp->tv_nsec = time * 1000000000 / kavail.tstamp.sampling_rate;
332c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return 0;
333c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
334c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
335c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentint compress_get_tstamp(struct compress *compress,
336c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			unsigned long *samples, unsigned int *sampling_rate)
337c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
338c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	struct snd_compr_tstamp ktstamp;
339c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
340c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (!is_compress_ready(compress))
34179c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, ENODEV, "device not ready");
342c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
343c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (ioctl(compress->fd, SNDRV_COMPRESS_TSTAMP, &ktstamp))
344c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return oops(compress, errno, "cannot get tstamp");
345c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
346c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	*samples = ktstamp.pcm_io_frames;
347c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	*sampling_rate = ktstamp.sampling_rate;
348c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return 0;
349c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
350c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
351c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentint compress_write(struct compress *compress, const void *buf, unsigned int size)
352c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
353c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	struct snd_compr_avail avail;
354c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	struct pollfd fds;
355c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	int to_write = 0;	/* zero indicates we haven't written yet */
356c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	int written, total = 0, ret;
357c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	const char* cbuf = buf;
358c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	const unsigned int frag_size = compress->config->fragment_size;
359c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
360c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (!(compress->flags & COMPRESS_IN))
36179c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, EINVAL, "Invalid flag set");
362c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (!is_compress_ready(compress))
36379c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, ENODEV, "device not ready");
364c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	fds.fd = compress->fd;
365c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	fds.events = POLLOUT;
366c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
367c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	/*TODO: treat auto start here first */
368c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	while (size) {
369c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		if (ioctl(compress->fd, SNDRV_COMPRESS_AVAIL, &avail))
370c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			return oops(compress, errno, "cannot get avail");
371c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
37279c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		/* We can write if we have at least one fragment available
37379c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		 * or there is enough space for all remaining data
37479c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		 */
37579c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		if ((avail.avail < frag_size) && (avail.avail < size)) {
37679c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent
37779c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent			if (compress->nonblocking)
37879c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent				return total;
37979c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent
380c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			ret = poll(&fds, 1, compress->max_poll_wait_ms);
381a85e245a09c028d36cbf04f233be10bc583691f5Richard Fitzgerald			if (fds.revents & POLLERR) {
382a85e245a09c028d36cbf04f233be10bc583691f5Richard Fitzgerald				return oops(compress, EIO, "poll returned error!");
383a85e245a09c028d36cbf04f233be10bc583691f5Richard Fitzgerald			}
384c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			/* A pause will cause -EBADFD or zero.
385c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			 * This is not an error, just stop writing */
386c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			if ((ret == 0) || (ret == -EBADFD))
387c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent				break;
388c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			if (ret < 0)
389c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent				return oops(compress, errno, "poll error");
390c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			if (fds.revents & POLLOUT) {
391c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent				continue;
392c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			}
393c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		}
394c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		/* write avail bytes */
395c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		if (size > avail.avail)
396c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			to_write =  avail.avail;
397c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		else
398c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			to_write = size;
399c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		written = write(compress->fd, cbuf, to_write);
400c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		/* If play was paused the write returns -EBADFD */
401c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		if (written == -EBADFD)
402c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			break;
403c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		if (written < 0)
404c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent			return oops(compress, errno, "write failed!");
405c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
406c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		size -= written;
407c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		cbuf += written;
408c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		total += written;
409c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	}
410c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return total;
411c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
412c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
413c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentint compress_read(struct compress *compress, void *buf, unsigned int size)
414c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
415f0c407825741bcb94952e4264efce66dee378411Eric Laurent	struct snd_compr_avail avail;
416f0c407825741bcb94952e4264efce66dee378411Eric Laurent	struct pollfd fds;
417f0c407825741bcb94952e4264efce66dee378411Eric Laurent	int to_read = 0;
418f0c407825741bcb94952e4264efce66dee378411Eric Laurent	int num_read, total = 0, ret;
419f0c407825741bcb94952e4264efce66dee378411Eric Laurent	char* cbuf = buf;
420f0c407825741bcb94952e4264efce66dee378411Eric Laurent	const unsigned int frag_size = compress->config->fragment_size;
421f0c407825741bcb94952e4264efce66dee378411Eric Laurent
422f0c407825741bcb94952e4264efce66dee378411Eric Laurent	if (!(compress->flags & COMPRESS_OUT))
42379c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, EINVAL, "Invalid flag set");
424f0c407825741bcb94952e4264efce66dee378411Eric Laurent	if (!is_compress_ready(compress))
42579c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, ENODEV, "device not ready");
426f0c407825741bcb94952e4264efce66dee378411Eric Laurent	fds.fd = compress->fd;
427f0c407825741bcb94952e4264efce66dee378411Eric Laurent	fds.events = POLLIN;
428f0c407825741bcb94952e4264efce66dee378411Eric Laurent
429f0c407825741bcb94952e4264efce66dee378411Eric Laurent	while (size) {
430f0c407825741bcb94952e4264efce66dee378411Eric Laurent		if (ioctl(compress->fd, SNDRV_COMPRESS_AVAIL, &avail))
431f0c407825741bcb94952e4264efce66dee378411Eric Laurent			return oops(compress, errno, "cannot get avail");
432f0c407825741bcb94952e4264efce66dee378411Eric Laurent
433f0c407825741bcb94952e4264efce66dee378411Eric Laurent		if ( (avail.avail < frag_size) && (avail.avail < size) ) {
434f0c407825741bcb94952e4264efce66dee378411Eric Laurent			/* Less than one fragment available and not at the
435f0c407825741bcb94952e4264efce66dee378411Eric Laurent			 * end of the read, so poll
436f0c407825741bcb94952e4264efce66dee378411Eric Laurent			 */
43779c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent			if (compress->nonblocking)
43879c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent				return total;
43979c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent
440f0c407825741bcb94952e4264efce66dee378411Eric Laurent			ret = poll(&fds, 1, compress->max_poll_wait_ms);
441a85e245a09c028d36cbf04f233be10bc583691f5Richard Fitzgerald			if (fds.revents & POLLERR) {
442a85e245a09c028d36cbf04f233be10bc583691f5Richard Fitzgerald				return oops(compress, EIO, "poll returned error!");
443a85e245a09c028d36cbf04f233be10bc583691f5Richard Fitzgerald			}
444f0c407825741bcb94952e4264efce66dee378411Eric Laurent			/* A pause will cause -EBADFD or zero.
445f0c407825741bcb94952e4264efce66dee378411Eric Laurent			 * This is not an error, just stop reading */
446f0c407825741bcb94952e4264efce66dee378411Eric Laurent			if ((ret == 0) || (ret == -EBADFD))
447f0c407825741bcb94952e4264efce66dee378411Eric Laurent				break;
448f0c407825741bcb94952e4264efce66dee378411Eric Laurent			if (ret < 0)
449f0c407825741bcb94952e4264efce66dee378411Eric Laurent				return oops(compress, errno, "poll error");
450f0c407825741bcb94952e4264efce66dee378411Eric Laurent			if (fds.revents & POLLIN) {
451f0c407825741bcb94952e4264efce66dee378411Eric Laurent				continue;
452f0c407825741bcb94952e4264efce66dee378411Eric Laurent			}
453f0c407825741bcb94952e4264efce66dee378411Eric Laurent		}
454f0c407825741bcb94952e4264efce66dee378411Eric Laurent		/* read avail bytes */
455f0c407825741bcb94952e4264efce66dee378411Eric Laurent		if (size > avail.avail)
456f0c407825741bcb94952e4264efce66dee378411Eric Laurent			to_read = avail.avail;
457f0c407825741bcb94952e4264efce66dee378411Eric Laurent		else
458f0c407825741bcb94952e4264efce66dee378411Eric Laurent			to_read = size;
459f0c407825741bcb94952e4264efce66dee378411Eric Laurent		num_read = read(compress->fd, cbuf, to_read);
460f0c407825741bcb94952e4264efce66dee378411Eric Laurent		/* If play was paused the read returns -EBADFD */
461f0c407825741bcb94952e4264efce66dee378411Eric Laurent		if (num_read == -EBADFD)
462f0c407825741bcb94952e4264efce66dee378411Eric Laurent			break;
463f0c407825741bcb94952e4264efce66dee378411Eric Laurent		if (num_read < 0)
464f0c407825741bcb94952e4264efce66dee378411Eric Laurent			return oops(compress, errno, "read failed!");
465f0c407825741bcb94952e4264efce66dee378411Eric Laurent
466f0c407825741bcb94952e4264efce66dee378411Eric Laurent		size -= num_read;
467f0c407825741bcb94952e4264efce66dee378411Eric Laurent		cbuf += num_read;
468f0c407825741bcb94952e4264efce66dee378411Eric Laurent		total += num_read;
469f0c407825741bcb94952e4264efce66dee378411Eric Laurent	}
470f0c407825741bcb94952e4264efce66dee378411Eric Laurent
471f0c407825741bcb94952e4264efce66dee378411Eric Laurent	return total;
472c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
473c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
474c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentint compress_start(struct compress *compress)
475c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
476c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (!is_compress_ready(compress))
47779c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, ENODEV, "device not ready");
478c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (ioctl(compress->fd, SNDRV_COMPRESS_START))
479c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return oops(compress, errno, "cannot start the stream");
480c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	compress->running = 1;
481c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return 0;
482c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
483c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
484c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
485c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentint compress_stop(struct compress *compress)
486c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
487c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (!is_compress_running(compress))
48879c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, ENODEV, "device not ready");
489c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (ioctl(compress->fd, SNDRV_COMPRESS_STOP))
490c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return oops(compress, errno, "cannot stop the stream");
491c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return 0;
492c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
493c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
494c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentint compress_pause(struct compress *compress)
495c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
496c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (!is_compress_running(compress))
49779c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, ENODEV, "device not ready");
498c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (ioctl(compress->fd, SNDRV_COMPRESS_PAUSE))
499c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return oops(compress, errno, "cannot pause the stream");
500c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return 0;
501c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
502c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
503c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentint compress_resume(struct compress *compress)
504c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
505c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (ioctl(compress->fd, SNDRV_COMPRESS_RESUME))
506c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return oops(compress, errno, "cannot resume the stream");
507c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return 0;
508c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
509c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
510c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentint compress_drain(struct compress *compress)
511c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
512c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (!is_compress_running(compress))
51379c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, ENODEV, "device not ready");
514c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (ioctl(compress->fd, SNDRV_COMPRESS_DRAIN))
515c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return oops(compress, errno, "cannot drain the stream");
516c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return 0;
517c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
518c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
519c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentint compress_partial_drain(struct compress *compress)
520c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
521c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (!is_compress_running(compress))
52279c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, ENODEV, "device not ready");
523c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
524c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (!compress->next_track)
52579c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, EPERM, "next track not signalled");
526c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (ioctl(compress->fd, SNDRV_COMPRESS_PARTIAL_DRAIN))
527c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return oops(compress, errno, "cannot drain the stream\n");
528c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	compress->next_track = 0;
529c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return 0;
530c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
531c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
532c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentint compress_next_track(struct compress *compress)
533c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
534c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (!is_compress_running(compress))
53579c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, ENODEV, "device not ready");
536c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
537c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (!compress->gapless_metadata)
53879c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, EPERM, "metadata not set");
539c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (ioctl(compress->fd, SNDRV_COMPRESS_NEXT_TRACK))
540c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return oops(compress, errno, "cannot set next track\n");
541c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	compress->next_track = 1;
542c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	compress->gapless_metadata = 0;
543c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return 0;
544c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
545c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
546c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentint compress_set_gapless_metadata(struct compress *compress,
547c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	struct compr_gapless_mdata *mdata)
548c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
549c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	struct snd_compr_metadata metadata;
550c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	int version;
551c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
552c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (!is_compress_ready(compress))
55379c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, ENODEV, "device not ready");
554c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
555c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	version = get_compress_version(compress);
556c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (version <= 0)
557c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return -1;
558c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
559c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (version < SNDRV_PROTOCOL_VERSION(0, 1, 1))
56079c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, ENXIO, "gapless apis not supported in kernel");
561c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
562c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	metadata.key = SNDRV_COMPRESS_ENCODER_PADDING;
563c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	metadata.value[0] = mdata->encoder_padding;
564c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (ioctl(compress->fd, SNDRV_COMPRESS_SET_METADATA, &metadata))
565c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return oops(compress, errno, "can't set metadata for stream\n");
566c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
567c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	metadata.key = SNDRV_COMPRESS_ENCODER_DELAY;
568c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	metadata.value[0] = mdata->encoder_delay;
569c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (ioctl(compress->fd, SNDRV_COMPRESS_SET_METADATA, &metadata))
570c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return oops(compress, errno, "can't set metadata for stream\n");
571c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	compress->gapless_metadata = 1;
572c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return 0;
573c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
574c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
575c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentbool is_codec_supported(unsigned int card, unsigned int device,
576c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		unsigned int flags, struct snd_codec *codec)
577c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
578c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	unsigned int dev_flag;
579c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	bool ret;
580c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	int fd;
581c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	char fn[256];
582c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
583c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	snprintf(fn, sizeof(fn), "/dev/snd/comprC%uD%u", card, device);
584c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
585c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (flags & COMPRESS_OUT)
586c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		dev_flag = O_RDONLY;
587c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	else
588c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		dev_flag = O_WRONLY;
589c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
590c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	fd = open(fn, dev_flag);
591c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	if (fd < 0)
592c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent		return oops(&bad_compress, errno, "cannot open device '%s'", fn);
593c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
594c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	ret = _is_codec_type_supported(fd, codec);
595c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
596c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	close(fd);
597c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	return ret;
598c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
599c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
600c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurentvoid compress_set_max_poll_wait(struct compress *compress, int milliseconds)
601c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent{
602c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent	compress->max_poll_wait_ms = milliseconds;
603c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent}
604c902d7fb4e0f2b086030f384ce217679775ca2d4Eric Laurent
60579c370788bfeac8e2951cc35844fb96f15f28159Eric Laurentvoid compress_nonblock(struct compress *compress, int nonblock)
60679c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent{
60779c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent	compress->nonblocking = !!nonblock;
60879c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent}
60979c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent
61079c370788bfeac8e2951cc35844fb96f15f28159Eric Laurentint compress_wait(struct compress *compress, int timeout_ms)
61179c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent{
61279c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent	struct pollfd fds;
61379c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent	int ret;
61479c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent
61579c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent	fds.fd = compress->fd;
61679c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent	fds.events = POLLOUT | POLLIN;
61779c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent
61879c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent	ret = poll(&fds, 1, timeout_ms);
619ab9b85b430eeef547c6f10496f8e2a904fd38c79Richard Fitzgerald	if (ret > 0) {
620ab9b85b430eeef547c6f10496f8e2a904fd38c79Richard Fitzgerald		if (fds.revents & POLLERR)
621ab9b85b430eeef547c6f10496f8e2a904fd38c79Richard Fitzgerald			return oops(compress, EIO, "poll returned error!");
622ab9b85b430eeef547c6f10496f8e2a904fd38c79Richard Fitzgerald		if (fds.revents & (POLLOUT | POLLIN))
623ab9b85b430eeef547c6f10496f8e2a904fd38c79Richard Fitzgerald			return 0;
624a85e245a09c028d36cbf04f233be10bc583691f5Richard Fitzgerald	}
625ab9b85b430eeef547c6f10496f8e2a904fd38c79Richard Fitzgerald	if (ret == 0)
626ab9b85b430eeef547c6f10496f8e2a904fd38c79Richard Fitzgerald		return oops(compress, ETIME, "poll timed out");
627ab9b85b430eeef547c6f10496f8e2a904fd38c79Richard Fitzgerald	if (ret < 0)
62879c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent		return oops(compress, errno, "poll error");
629ab9b85b430eeef547c6f10496f8e2a904fd38c79Richard Fitzgerald
630ab9b85b430eeef547c6f10496f8e2a904fd38c79Richard Fitzgerald	return oops(compress, EIO, "poll signalled unhandled event");
63179c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent}
63279c370788bfeac8e2951cc35844fb96f15f28159Eric Laurent
633