blob: 7422c4b6d5a3fa3ceed2ac8ab3d0543d84934b73 [file] [log] [blame]
Eric Laurentc902d7f2013-03-08 14:50:45 -08001/*
2 * BSD LICENSE
3 *
4 * tinycompress library for compress audio offload in alsa
5 * Copyright (c) 2011-2012, Intel Corporation
6 * All rights reserved.
7 *
8 * Author: Vinod Koul <vinod.koul@linux.intel.com>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * Neither the name of Intel Corporation nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 * LGPL LICENSE
35 *
36 * tinycompress library for compress audio offload in alsa
37 * Copyright (c) 2011-2012, Intel Corporation.
38 *
39 *
40 * This program is free software; you can redistribute it and/or modify it
41 * under the terms and conditions of the GNU Lesser General Public License,
42 * version 2.1, as published by the Free Software Foundation.
43 *
44 * This program is distributed in the hope it will be useful, but WITHOUT
45 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
46 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
47 * License for more details.
48 *
49 * You should have received a copy of the GNU Lesser General Public License
50 * along with this program; if not, write to
51 * the Free Software Foundation, Inc.,
52 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
53 */
54
55#include <stdio.h>
56#include <stdlib.h>
57#include <fcntl.h>
58#include <stdarg.h>
59#include <string.h>
60#include <errno.h>
61#include <unistd.h>
62#include <poll.h>
63#include <stdbool.h>
64#include <sys/ioctl.h>
65#include <sys/mman.h>
66#include <sys/time.h>
67#include <limits.h>
68
69#include <linux/types.h>
70#include <linux/ioctl.h>
71#define __force
72#define __bitwise
73#define __user
74#include <sound/asound.h>
Eric Laurent79c37072013-06-07 10:50:05 -070075#include "sound/compress_params.h"
76#include "sound/compress_offload.h"
77#include "tinycompress/tinycompress.h"
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +010078#include "compress_ops.h"
79#include "snd_utils.h"
Eric Laurentc902d7f2013-03-08 14:50:45 -080080
81#define COMPR_ERR_MAX 128
82
83/* Default maximum time we will wait in a poll() - 20 seconds */
84#define DEFAULT_MAX_POLL_WAIT_MS 20000
85
86struct compress {
87 int fd;
88 unsigned int flags;
89 char error[COMPR_ERR_MAX];
90 struct compr_config *config;
91 int running;
92 int max_poll_wait_ms;
Eric Laurent79c37072013-06-07 10:50:05 -070093 int nonblocking;
Eric Laurentc902d7f2013-03-08 14:50:45 -080094 unsigned int gapless_metadata;
95 unsigned int next_track;
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +010096
97 struct compress_ops *ops;
98 void *data;
99 void *snd_node;
Eric Laurentc902d7f2013-03-08 14:50:45 -0800100};
101
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100102extern struct compress_ops compr_hw_ops;
103extern struct compress_ops compr_plug_ops;
104
Eric Laurentc902d7f2013-03-08 14:50:45 -0800105static int oops(struct compress *compress, int e, const char *fmt, ...)
106{
107 va_list ap;
108 int sz;
109
110 va_start(ap, fmt);
111 vsnprintf(compress->error, COMPR_ERR_MAX, fmt, ap);
112 va_end(ap);
113 sz = strlen(compress->error);
114
Eric Laurent79c37072013-06-07 10:50:05 -0700115 snprintf(compress->error + sz, COMPR_ERR_MAX - sz,
116 ": %s", strerror(e));
117 errno = e;
118
119 return -1;
Eric Laurentc902d7f2013-03-08 14:50:45 -0800120}
121
122const char *compress_get_error(struct compress *compress)
123{
124 return compress->error;
125}
126static struct compress bad_compress = {
127 .fd = -1,
128};
129
130int is_compress_running(struct compress *compress)
131{
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100132 return ((compress->fd >= 0) && compress->running) ? 1 : 0;
Eric Laurentc902d7f2013-03-08 14:50:45 -0800133}
134
135int is_compress_ready(struct compress *compress)
136{
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100137 return (compress->fd >= 0) ? 1 : 0;
Eric Laurentc902d7f2013-03-08 14:50:45 -0800138}
139
140static int get_compress_version(struct compress *compress)
141{
142 int version = 0;
143
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100144 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_IOCTL_VERSION, &version)) {
Eric Laurentc902d7f2013-03-08 14:50:45 -0800145 oops(compress, errno, "cant read version");
146 return -1;
147 }
148 return version;
149}
150
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100151static bool _is_codec_type_supported(struct compress_ops *ops, void *data,
152 struct snd_codec *codec)
Eric Laurentc902d7f2013-03-08 14:50:45 -0800153{
154 struct snd_compr_caps caps;
155 bool found = false;
156 unsigned int i;
157
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100158 if (ops->ioctl(data, SNDRV_COMPRESS_GET_CAPS, &caps)) {
Eric Laurentc902d7f2013-03-08 14:50:45 -0800159 oops(&bad_compress, errno, "cannot get device caps");
160 return false;
161 }
162
163 for (i = 0; i < caps.num_codecs; i++) {
164 if (caps.codecs[i] == codec->id) {
165 /* found the codec */
166 found = true;
167 break;
168 }
169 }
170 /* TODO: match the codec properties */
171 return found;
172}
173
174static inline void
175fill_compress_params(struct compr_config *config, struct snd_compr_params *params)
176{
177 params->buffer.fragment_size = config->fragment_size;
178 params->buffer.fragments = config->fragments;
179 memcpy(&params->codec, config->codec, sizeof(params->codec));
180}
181
182struct compress *compress_open(unsigned int card, unsigned int device,
183 unsigned int flags, struct compr_config *config)
184{
185 struct compress *compress;
186 struct snd_compr_params params;
187 struct snd_compr_caps caps;
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100188 int compress_type;
Eric Laurentc902d7f2013-03-08 14:50:45 -0800189
Eric Laurent79c37072013-06-07 10:50:05 -0700190 if (!config) {
191 oops(&bad_compress, EINVAL, "passed bad config");
192 return &bad_compress;
193 }
194
Eric Laurentc902d7f2013-03-08 14:50:45 -0800195 compress = calloc(1, sizeof(struct compress));
Eric Laurent79c37072013-06-07 10:50:05 -0700196 if (!compress) {
Eric Laurentc902d7f2013-03-08 14:50:45 -0800197 oops(&bad_compress, errno, "cannot allocate compress object");
198 return &bad_compress;
199 }
200
201 compress->next_track = 0;
202 compress->gapless_metadata = 0;
203 compress->config = calloc(1, sizeof(*config));
204 if (!compress->config)
205 goto input_fail;
Eric Laurentc902d7f2013-03-08 14:50:45 -0800206
Eric Laurentc902d7f2013-03-08 14:50:45 -0800207 compress->max_poll_wait_ms = DEFAULT_MAX_POLL_WAIT_MS;
208
209 compress->flags = flags;
210 if (!((flags & COMPRESS_OUT) || (flags & COMPRESS_IN))) {
Eric Laurent79c37072013-06-07 10:50:05 -0700211 oops(&bad_compress, EINVAL, "can't deduce device direction from given flags");
Eric Laurentc902d7f2013-03-08 14:50:45 -0800212 goto config_fail;
213 }
Eric Laurentc902d7f2013-03-08 14:50:45 -0800214
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100215 compress->snd_node = snd_utils_get_dev_node(card, device, NODE_COMPRESS);
216 compress_type = snd_utils_get_node_type(compress->snd_node);
217 if (compress_type == SND_NODE_TYPE_PLUGIN)
218 compress->ops = &compr_plug_ops;
219 else
220 compress->ops = &compr_hw_ops;
221
222 compress->fd = compress->ops->open(card, device, flags,
223 &compress->data, compress->snd_node);
Eric Laurentc902d7f2013-03-08 14:50:45 -0800224 if (compress->fd < 0) {
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100225 oops(&bad_compress, errno, "cannot open card(%u) device(%u)",
226 card, device);
Eric Laurentc902d7f2013-03-08 14:50:45 -0800227 goto config_fail;
228 }
229
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100230 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_GET_CAPS, &caps)) {
Eric Laurentc902d7f2013-03-08 14:50:45 -0800231 oops(compress, errno, "cannot get device caps");
232 goto codec_fail;
233 }
234
235 /* If caller passed "don't care" fill in default values */
236 if ((config->fragment_size == 0) || (config->fragments == 0)) {
237 config->fragment_size = caps.min_fragment_size;
238 config->fragments = caps.max_fragments;
239 }
240
241#if 0
242 /* FIXME need to turn this On when DSP supports
243 * and treat in no support case
244 */
245 if (_is_codec_supported(compress, config, &caps) == false) {
246 oops(compress, errno, "codec not supported\n");
247 goto codec_fail;
248 }
249#endif
Eric Laurent79c37072013-06-07 10:50:05 -0700250
251 memcpy(compress->config, config, sizeof(*compress->config));
Eric Laurentc902d7f2013-03-08 14:50:45 -0800252 fill_compress_params(config, &params);
253
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100254 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_SET_PARAMS, &params)) {
Eric Laurentc902d7f2013-03-08 14:50:45 -0800255 oops(&bad_compress, errno, "cannot set device");
256 goto codec_fail;
257 }
258
259 return compress;
260
261codec_fail:
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100262 snd_utils_put_dev_node(compress->snd_node);
263 compress->ops->close(compress->data);
Eric Laurentc902d7f2013-03-08 14:50:45 -0800264 compress->fd = -1;
265config_fail:
266 free(compress->config);
267input_fail:
268 free(compress);
269 return &bad_compress;
270}
271
272void compress_close(struct compress *compress)
273{
274 if (compress == &bad_compress)
275 return;
276
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100277 snd_utils_put_dev_node(compress->snd_node);
278 compress->ops->close(compress->data);
Eric Laurentc902d7f2013-03-08 14:50:45 -0800279 compress->running = 0;
280 compress->fd = -1;
281 free(compress->config);
282 free(compress);
283}
284
285int compress_get_hpointer(struct compress *compress,
286 unsigned int *avail, struct timespec *tstamp)
287{
288 struct snd_compr_avail kavail;
289 __u64 time;
290
291 if (!is_compress_ready(compress))
Eric Laurent79c37072013-06-07 10:50:05 -0700292 return oops(compress, ENODEV, "device not ready");
Eric Laurentc902d7f2013-03-08 14:50:45 -0800293
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100294 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_AVAIL, &kavail))
Eric Laurentc902d7f2013-03-08 14:50:45 -0800295 return oops(compress, errno, "cannot get avail");
296 if (0 == kavail.tstamp.sampling_rate)
Eric Laurent79c37072013-06-07 10:50:05 -0700297 return oops(compress, ENODATA, "sample rate unknown");
Eric Laurentc902d7f2013-03-08 14:50:45 -0800298 *avail = (unsigned int)kavail.avail;
299 time = kavail.tstamp.pcm_io_frames / kavail.tstamp.sampling_rate;
300 tstamp->tv_sec = time;
301 time = kavail.tstamp.pcm_io_frames % kavail.tstamp.sampling_rate;
302 tstamp->tv_nsec = time * 1000000000 / kavail.tstamp.sampling_rate;
303 return 0;
304}
305
306int compress_get_tstamp(struct compress *compress,
307 unsigned long *samples, unsigned int *sampling_rate)
308{
309 struct snd_compr_tstamp ktstamp;
310
311 if (!is_compress_ready(compress))
Eric Laurent79c37072013-06-07 10:50:05 -0700312 return oops(compress, ENODEV, "device not ready");
Eric Laurentc902d7f2013-03-08 14:50:45 -0800313
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100314 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_TSTAMP, &ktstamp))
Eric Laurentc902d7f2013-03-08 14:50:45 -0800315 return oops(compress, errno, "cannot get tstamp");
316
317 *samples = ktstamp.pcm_io_frames;
318 *sampling_rate = ktstamp.sampling_rate;
319 return 0;
320}
321
322int compress_write(struct compress *compress, const void *buf, unsigned int size)
323{
324 struct snd_compr_avail avail;
325 struct pollfd fds;
326 int to_write = 0; /* zero indicates we haven't written yet */
327 int written, total = 0, ret;
328 const char* cbuf = buf;
329 const unsigned int frag_size = compress->config->fragment_size;
330
331 if (!(compress->flags & COMPRESS_IN))
Eric Laurent79c37072013-06-07 10:50:05 -0700332 return oops(compress, EINVAL, "Invalid flag set");
Eric Laurentc902d7f2013-03-08 14:50:45 -0800333 if (!is_compress_ready(compress))
Eric Laurent79c37072013-06-07 10:50:05 -0700334 return oops(compress, ENODEV, "device not ready");
Eric Laurentc902d7f2013-03-08 14:50:45 -0800335 fds.events = POLLOUT;
336
337 /*TODO: treat auto start here first */
338 while (size) {
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100339 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_AVAIL, &avail))
Eric Laurentc902d7f2013-03-08 14:50:45 -0800340 return oops(compress, errno, "cannot get avail");
341
Eric Laurent79c37072013-06-07 10:50:05 -0700342 /* We can write if we have at least one fragment available
343 * or there is enough space for all remaining data
344 */
345 if ((avail.avail < frag_size) && (avail.avail < size)) {
346
347 if (compress->nonblocking)
348 return total;
349
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100350 ret = compress->ops->poll(compress->data, &fds, 1,
351 compress->max_poll_wait_ms);
Richard Fitzgeralda85e2452013-08-29 09:32:02 +0100352 if (fds.revents & POLLERR) {
353 return oops(compress, EIO, "poll returned error!");
354 }
Eric Laurentc902d7f2013-03-08 14:50:45 -0800355 /* A pause will cause -EBADFD or zero.
356 * This is not an error, just stop writing */
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100357 if ((ret == 0) || (ret < 0 && errno == EBADFD))
Eric Laurentc902d7f2013-03-08 14:50:45 -0800358 break;
359 if (ret < 0)
360 return oops(compress, errno, "poll error");
361 if (fds.revents & POLLOUT) {
362 continue;
363 }
Eric Laurentc902d7f2013-03-08 14:50:45 -0800364 }
365 /* write avail bytes */
366 if (size > avail.avail)
367 to_write = avail.avail;
368 else
369 to_write = size;
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100370 written = compress->ops->write(compress->data, cbuf, to_write);
371 if (written < 0) {
372 /* If play was paused the write returns -EBADFD */
373 if (errno == EBADFD)
374 break;
Eric Laurentc902d7f2013-03-08 14:50:45 -0800375 return oops(compress, errno, "write failed!");
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100376 }
Eric Laurentc902d7f2013-03-08 14:50:45 -0800377
378 size -= written;
379 cbuf += written;
380 total += written;
381 }
382 return total;
383}
384
385int compress_read(struct compress *compress, void *buf, unsigned int size)
386{
Eric Laurentf0c40782013-05-02 18:10:20 -0700387 struct snd_compr_avail avail;
388 struct pollfd fds;
389 int to_read = 0;
390 int num_read, total = 0, ret;
391 char* cbuf = buf;
392 const unsigned int frag_size = compress->config->fragment_size;
393
394 if (!(compress->flags & COMPRESS_OUT))
Eric Laurent79c37072013-06-07 10:50:05 -0700395 return oops(compress, EINVAL, "Invalid flag set");
Eric Laurentf0c40782013-05-02 18:10:20 -0700396 if (!is_compress_ready(compress))
Eric Laurent79c37072013-06-07 10:50:05 -0700397 return oops(compress, ENODEV, "device not ready");
Eric Laurentf0c40782013-05-02 18:10:20 -0700398 fds.events = POLLIN;
399
400 while (size) {
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100401 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_AVAIL, &avail))
Eric Laurentf0c40782013-05-02 18:10:20 -0700402 return oops(compress, errno, "cannot get avail");
403
404 if ( (avail.avail < frag_size) && (avail.avail < size) ) {
405 /* Less than one fragment available and not at the
406 * end of the read, so poll
407 */
Eric Laurent79c37072013-06-07 10:50:05 -0700408 if (compress->nonblocking)
409 return total;
410
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100411 ret = compress->ops->poll(compress->data, &fds, 1,
412 compress->max_poll_wait_ms);
Richard Fitzgeralda85e2452013-08-29 09:32:02 +0100413 if (fds.revents & POLLERR) {
414 return oops(compress, EIO, "poll returned error!");
415 }
Eric Laurentf0c40782013-05-02 18:10:20 -0700416 /* A pause will cause -EBADFD or zero.
417 * This is not an error, just stop reading */
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100418 if ((ret == 0) || (ret < 0 && errno == EBADFD))
Eric Laurentf0c40782013-05-02 18:10:20 -0700419 break;
420 if (ret < 0)
421 return oops(compress, errno, "poll error");
422 if (fds.revents & POLLIN) {
423 continue;
424 }
Eric Laurentf0c40782013-05-02 18:10:20 -0700425 }
426 /* read avail bytes */
427 if (size > avail.avail)
428 to_read = avail.avail;
429 else
430 to_read = size;
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100431 num_read = compress->ops->read(compress->data, cbuf, to_read);
432 if (num_read < 0) {
433 /* If play was paused the read returns -EBADFD */
434 if (errno == EBADFD)
435 break;
Eric Laurentf0c40782013-05-02 18:10:20 -0700436 return oops(compress, errno, "read failed!");
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100437 }
Eric Laurentf0c40782013-05-02 18:10:20 -0700438
439 size -= num_read;
440 cbuf += num_read;
441 total += num_read;
442 }
443
444 return total;
Eric Laurentc902d7f2013-03-08 14:50:45 -0800445}
446
447int compress_start(struct compress *compress)
448{
449 if (!is_compress_ready(compress))
Eric Laurent79c37072013-06-07 10:50:05 -0700450 return oops(compress, ENODEV, "device not ready");
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100451 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_START))
Eric Laurentc902d7f2013-03-08 14:50:45 -0800452 return oops(compress, errno, "cannot start the stream");
453 compress->running = 1;
454 return 0;
455
456}
457
458int compress_stop(struct compress *compress)
459{
460 if (!is_compress_running(compress))
Eric Laurent79c37072013-06-07 10:50:05 -0700461 return oops(compress, ENODEV, "device not ready");
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100462 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_STOP))
Eric Laurentc902d7f2013-03-08 14:50:45 -0800463 return oops(compress, errno, "cannot stop the stream");
464 return 0;
465}
466
467int compress_pause(struct compress *compress)
468{
469 if (!is_compress_running(compress))
Eric Laurent79c37072013-06-07 10:50:05 -0700470 return oops(compress, ENODEV, "device not ready");
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100471 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_PAUSE))
Eric Laurentc902d7f2013-03-08 14:50:45 -0800472 return oops(compress, errno, "cannot pause the stream");
473 return 0;
474}
475
476int compress_resume(struct compress *compress)
477{
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100478 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_RESUME))
Eric Laurentc902d7f2013-03-08 14:50:45 -0800479 return oops(compress, errno, "cannot resume the stream");
480 return 0;
481}
482
483int compress_drain(struct compress *compress)
484{
485 if (!is_compress_running(compress))
Eric Laurent79c37072013-06-07 10:50:05 -0700486 return oops(compress, ENODEV, "device not ready");
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100487 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_DRAIN))
Eric Laurentc902d7f2013-03-08 14:50:45 -0800488 return oops(compress, errno, "cannot drain the stream");
489 return 0;
490}
491
492int compress_partial_drain(struct compress *compress)
493{
494 if (!is_compress_running(compress))
Eric Laurent79c37072013-06-07 10:50:05 -0700495 return oops(compress, ENODEV, "device not ready");
Eric Laurentc902d7f2013-03-08 14:50:45 -0800496
497 if (!compress->next_track)
Eric Laurent79c37072013-06-07 10:50:05 -0700498 return oops(compress, EPERM, "next track not signalled");
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100499 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_PARTIAL_DRAIN))
Eric Laurentc902d7f2013-03-08 14:50:45 -0800500 return oops(compress, errno, "cannot drain the stream\n");
501 compress->next_track = 0;
502 return 0;
503}
504
505int compress_next_track(struct compress *compress)
506{
507 if (!is_compress_running(compress))
Eric Laurent79c37072013-06-07 10:50:05 -0700508 return oops(compress, ENODEV, "device not ready");
Eric Laurentc902d7f2013-03-08 14:50:45 -0800509
510 if (!compress->gapless_metadata)
Eric Laurent79c37072013-06-07 10:50:05 -0700511 return oops(compress, EPERM, "metadata not set");
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100512 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_NEXT_TRACK))
Eric Laurentc902d7f2013-03-08 14:50:45 -0800513 return oops(compress, errno, "cannot set next track\n");
514 compress->next_track = 1;
515 compress->gapless_metadata = 0;
516 return 0;
517}
518
519int compress_set_gapless_metadata(struct compress *compress,
520 struct compr_gapless_mdata *mdata)
521{
522 struct snd_compr_metadata metadata;
523 int version;
524
525 if (!is_compress_ready(compress))
Eric Laurent79c37072013-06-07 10:50:05 -0700526 return oops(compress, ENODEV, "device not ready");
Eric Laurentc902d7f2013-03-08 14:50:45 -0800527
528 version = get_compress_version(compress);
529 if (version <= 0)
530 return -1;
531
532 if (version < SNDRV_PROTOCOL_VERSION(0, 1, 1))
Eric Laurent79c37072013-06-07 10:50:05 -0700533 return oops(compress, ENXIO, "gapless apis not supported in kernel");
Eric Laurentc902d7f2013-03-08 14:50:45 -0800534
535 metadata.key = SNDRV_COMPRESS_ENCODER_PADDING;
536 metadata.value[0] = mdata->encoder_padding;
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100537 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_SET_METADATA, &metadata))
Eric Laurentc902d7f2013-03-08 14:50:45 -0800538 return oops(compress, errno, "can't set metadata for stream\n");
539
540 metadata.key = SNDRV_COMPRESS_ENCODER_DELAY;
541 metadata.value[0] = mdata->encoder_delay;
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100542 if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_SET_METADATA, &metadata))
Eric Laurentc902d7f2013-03-08 14:50:45 -0800543 return oops(compress, errno, "can't set metadata for stream\n");
544 compress->gapless_metadata = 1;
545 return 0;
546}
547
Aniket Kumar Lata8751cec2019-01-18 16:45:01 -0800548#ifdef ENABLE_EXTENDED_COMPRESS_FORMAT
549int compress_set_next_track_param(struct compress *compress,
550 union snd_codec_options *codec_options)
551{
552 if (!is_compress_running(compress))
553 return oops(compress, ENODEV, "device not ready");
554
555 if (ioctl(compress->fd, SNDRV_COMPRESS_SET_NEXT_TRACK_PARAM, codec_options))
556 return oops(compress, errno, "cannot set next track params\n");
557 return 0;
558}
559#endif
560
Eric Laurentc902d7f2013-03-08 14:50:45 -0800561bool is_codec_supported(unsigned int card, unsigned int device,
562 unsigned int flags, struct snd_codec *codec)
563{
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100564 struct compress_ops *ops;
565 void *snd_node, *data;
Eric Laurentc902d7f2013-03-08 14:50:45 -0800566 bool ret;
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100567 int compress_type, fd;
Eric Laurentc902d7f2013-03-08 14:50:45 -0800568
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100569 snd_node = snd_utils_get_dev_node(card, device, NODE_COMPRESS);
570 compress_type = snd_utils_get_node_type(snd_node);
571 if (compress_type == SND_NODE_TYPE_PLUGIN)
572 ops = &compr_plug_ops;
Eric Laurentc902d7f2013-03-08 14:50:45 -0800573 else
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100574 ops = &compr_hw_ops;
Eric Laurentc902d7f2013-03-08 14:50:45 -0800575
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100576 fd = ops->open(card, device, flags, &data, NULL);
Eric Laurentc902d7f2013-03-08 14:50:45 -0800577 if (fd < 0)
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100578 return oops(&bad_compress, errno, "cannot open card %u, device %u",
579 card, device);
Eric Laurentc902d7f2013-03-08 14:50:45 -0800580
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100581 ret = _is_codec_type_supported(ops, data, codec);
Eric Laurentc902d7f2013-03-08 14:50:45 -0800582
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100583 snd_utils_put_dev_node(snd_node);
584 ops->close(data);
Eric Laurentc902d7f2013-03-08 14:50:45 -0800585 return ret;
586}
587
588void compress_set_max_poll_wait(struct compress *compress, int milliseconds)
589{
590 compress->max_poll_wait_ms = milliseconds;
591}
592
Eric Laurent79c37072013-06-07 10:50:05 -0700593void compress_nonblock(struct compress *compress, int nonblock)
594{
595 compress->nonblocking = !!nonblock;
596}
597
598int compress_wait(struct compress *compress, int timeout_ms)
599{
600 struct pollfd fds;
601 int ret;
602
Eric Laurent79c37072013-06-07 10:50:05 -0700603 fds.events = POLLOUT | POLLIN;
604
Vidyakumar Athota931e7cf2020-12-10 12:05:54 +0100605 ret = compress->ops->poll(compress->data, &fds, 1, timeout_ms);
Richard Fitzgeraldab9b85b2013-10-22 11:51:58 +0100606 if (ret > 0) {
607 if (fds.revents & POLLERR)
608 return oops(compress, EIO, "poll returned error!");
609 if (fds.revents & (POLLOUT | POLLIN))
610 return 0;
Richard Fitzgeralda85e2452013-08-29 09:32:02 +0100611 }
Richard Fitzgeraldab9b85b2013-10-22 11:51:58 +0100612 if (ret == 0)
613 return oops(compress, ETIME, "poll timed out");
614 if (ret < 0)
Eric Laurent79c37072013-06-07 10:50:05 -0700615 return oops(compress, errno, "poll error");
Richard Fitzgeraldab9b85b2013-10-22 11:51:58 +0100616
617 return oops(compress, EIO, "poll signalled unhandled event");
Eric Laurent79c37072013-06-07 10:50:05 -0700618}
619
Aniket Kumar Lata8751cec2019-01-18 16:45:01 -0800620#ifdef ENABLE_EXTENDED_COMPRESS_FORMAT
621int compress_get_metadata(struct compress *compress,
622 struct snd_compr_metadata *mdata) {
623 int version;
624 if (!is_compress_ready(compress))
625 return oops(compress, ENODEV, "device not ready");
626
627 version = get_compress_version(compress);
628 if (version <= 0)
629 return -1;
630
631 if (ioctl(compress->fd, SNDRV_COMPRESS_GET_METADATA, mdata)) {
632 return oops(compress, errno, "can't get metadata for stream\n");
633 }
634 return 0;
635}
636
637int compress_set_metadata(struct compress *compress,
638 struct snd_compr_metadata *mdata) {
639
640 int version;
641 if (!is_compress_ready(compress))
642 return oops(compress, ENODEV, "device not ready");
643
644 version = get_compress_version(compress);
645 if (version <= 0)
646 return -1;
647
648 if (ioctl(compress->fd, SNDRV_COMPRESS_SET_METADATA, mdata)) {
649 return oops(compress, errno, "can't set metadata for stream\n");
650 }
651 return 0;
652}
653#endif