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(¶ms->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, ¶ms);
253*de0de752SAndroid Build Coastguard Worker
254*de0de752SAndroid Build Coastguard Worker if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_SET_PARAMS, ¶ms)) {
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(¶ms.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, ¶ms))
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