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