• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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>
75 #include "sound/compress_params.h"
76 #include "sound/compress_offload.h"
77 #include "tinycompress/tinycompress.h"
78 #include "compress_ops.h"
79 #include "snd_utils.h"
80 
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 
86 struct 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;
93 	int nonblocking;
94 	unsigned int gapless_metadata;
95 	unsigned int next_track;
96 
97 	struct compress_ops *ops;
98 	void *data;
99 	void *snd_node;
100 };
101 
102 extern struct compress_ops compr_hw_ops;
103 extern struct compress_ops compr_plug_ops;
104 
oops(struct compress * compress,int e,const char * fmt,...)105 static 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 
115 	snprintf(compress->error + sz, COMPR_ERR_MAX - sz,
116 		": %s", strerror(e));
117 	errno = e;
118 
119 	return -1;
120 }
121 
compress_get_error(struct compress * compress)122 const char *compress_get_error(struct compress *compress)
123 {
124 	return compress->error;
125 }
126 static struct compress bad_compress = {
127 	.fd = -1,
128 };
129 
is_compress_running(struct compress * compress)130 int is_compress_running(struct compress *compress)
131 {
132 	return ((compress->fd >= 0) && compress->running) ? 1 : 0;
133 }
134 
is_compress_ready(struct compress * compress)135 int is_compress_ready(struct compress *compress)
136 {
137 	return (compress->fd >= 0) ? 1 : 0;
138 }
139 
get_compress_version(struct compress * compress)140 static int get_compress_version(struct compress *compress)
141 {
142 	int version = 0;
143 
144 	if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_IOCTL_VERSION, &version)) {
145 		oops(compress, errno, "cant read version");
146 		return -1;
147 	}
148 	return version;
149 }
150 
_is_codec_type_supported(struct compress_ops * ops,void * data,struct snd_codec * codec)151 static bool _is_codec_type_supported(struct compress_ops *ops, void *data,
152 		struct snd_codec *codec)
153 {
154 	struct snd_compr_caps caps;
155 	bool found = false;
156 	unsigned int i;
157 
158 	if (ops->ioctl(data, SNDRV_COMPRESS_GET_CAPS, &caps)) {
159 		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 
174 static inline void
fill_compress_params(struct compr_config * config,struct snd_compr_params * params)175 fill_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 
compress_open(unsigned int card,unsigned int device,unsigned int flags,struct compr_config * config)182 struct 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;
188 	int compress_type;
189 
190 	if (!config) {
191 		oops(&bad_compress, EINVAL, "passed bad config");
192 		return &bad_compress;
193 	}
194 
195 	compress = calloc(1, sizeof(struct compress));
196 	if (!compress) {
197 		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;
206 
207 	compress->max_poll_wait_ms = DEFAULT_MAX_POLL_WAIT_MS;
208 
209 	compress->flags = flags;
210 	if (!((flags & COMPRESS_OUT) || (flags & COMPRESS_IN))) {
211 		oops(&bad_compress, EINVAL, "can't deduce device direction from given flags");
212 		goto config_fail;
213 	}
214 
215 	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);
224 	if (compress->fd < 0) {
225 		oops(&bad_compress, errno, "cannot open card(%u) device(%u)",
226 			card, device);
227 		goto config_fail;
228 	}
229 
230 	if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_GET_CAPS, &caps)) {
231 		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
250 
251 	memcpy(compress->config, config, sizeof(*compress->config));
252 	fill_compress_params(config, &params);
253 
254 	if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_SET_PARAMS, &params)) {
255 		oops(&bad_compress, errno, "cannot set device");
256 		goto codec_fail;
257 	}
258 
259 	return compress;
260 
261 codec_fail:
262 	snd_utils_put_dev_node(compress->snd_node);
263 	compress->ops->close(compress->data);
264 	compress->fd = -1;
265 config_fail:
266 	free(compress->config);
267 input_fail:
268 	free(compress);
269 	return &bad_compress;
270 }
271 
compress_close(struct compress * compress)272 void compress_close(struct compress *compress)
273 {
274 	if (compress == &bad_compress)
275 		return;
276 
277 	snd_utils_put_dev_node(compress->snd_node);
278 	compress->ops->close(compress->data);
279 	compress->running = 0;
280 	compress->fd = -1;
281 	free(compress->config);
282 	free(compress);
283 }
284 
compress_get_hpointer(struct compress * compress,unsigned int * avail,struct timespec * tstamp)285 int 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))
292 		return oops(compress, ENODEV, "device not ready");
293 
294 	if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_AVAIL, &kavail))
295 		return oops(compress, errno, "cannot get avail");
296 	if (0 == kavail.tstamp.sampling_rate)
297 		return oops(compress, ENODATA, "sample rate unknown");
298 	*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 
compress_get_tstamp(struct compress * compress,unsigned long * samples,unsigned int * sampling_rate)306 int 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))
312 		return oops(compress, ENODEV, "device not ready");
313 
314 	if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_TSTAMP, &ktstamp))
315 		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 
compress_write(struct compress * compress,const void * buf,unsigned int size)322 int 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))
332 		return oops(compress, EINVAL, "Invalid flag set");
333 	if (!is_compress_ready(compress))
334 		return oops(compress, ENODEV, "device not ready");
335 	fds.events = POLLOUT;
336 
337 	/*TODO: treat auto start here first */
338 	while (size) {
339 		if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_AVAIL, &avail))
340 			return oops(compress, errno, "cannot get avail");
341 
342 		/* 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 
350 			ret = compress->ops->poll(compress->data, &fds, 1,
351 								compress->max_poll_wait_ms);
352 			if (fds.revents & POLLERR) {
353 				return oops(compress, EIO, "poll returned error!");
354 			}
355 			/* A pause will cause -EBADFD or zero.
356 			 * This is not an error, just stop writing */
357 			if ((ret == 0) || (ret < 0 && errno == EBADFD))
358 				break;
359 			if (ret < 0)
360 				return oops(compress, errno, "poll error");
361 			if (fds.revents & POLLOUT) {
362 				continue;
363 			}
364 		}
365 		/* write avail bytes */
366 		if (size > avail.avail)
367 			to_write =  avail.avail;
368 		else
369 			to_write = size;
370 		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;
375 			return oops(compress, errno, "write failed!");
376 		}
377 
378 		size -= written;
379 		cbuf += written;
380 		total += written;
381 	}
382 	return total;
383 }
384 
compress_read(struct compress * compress,void * buf,unsigned int size)385 int compress_read(struct compress *compress, void *buf, unsigned int size)
386 {
387 	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))
395 		return oops(compress, EINVAL, "Invalid flag set");
396 	if (!is_compress_ready(compress))
397 		return oops(compress, ENODEV, "device not ready");
398 	fds.events = POLLIN;
399 
400 	while (size) {
401 		if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_AVAIL, &avail))
402 			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 			 */
408 			if (compress->nonblocking)
409 				return total;
410 
411 			ret = compress->ops->poll(compress->data, &fds, 1,
412 							compress->max_poll_wait_ms);
413 			if (fds.revents & POLLERR) {
414 				return oops(compress, EIO, "poll returned error!");
415 			}
416 			/* A pause will cause -EBADFD or zero.
417 			 * This is not an error, just stop reading */
418 			if ((ret == 0) || (ret < 0 && errno == EBADFD))
419 				break;
420 			if (ret < 0)
421 				return oops(compress, errno, "poll error");
422 			if (fds.revents & POLLIN) {
423 				continue;
424 			}
425 		}
426 		/* read avail bytes */
427 		if (size > avail.avail)
428 			to_read = avail.avail;
429 		else
430 			to_read = size;
431 		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;
436 			return oops(compress, errno, "read failed!");
437 		}
438 
439 		size -= num_read;
440 		cbuf += num_read;
441 		total += num_read;
442 	}
443 
444 	return total;
445 }
446 
compress_start(struct compress * compress)447 int compress_start(struct compress *compress)
448 {
449 	if (!is_compress_ready(compress))
450 		return oops(compress, ENODEV, "device not ready");
451 	if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_START))
452 		return oops(compress, errno, "cannot start the stream");
453 	compress->running = 1;
454 	return 0;
455 
456 }
457 
compress_stop(struct compress * compress)458 int compress_stop(struct compress *compress)
459 {
460 	if (!is_compress_running(compress))
461 		return oops(compress, ENODEV, "device not ready");
462 	if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_STOP))
463 		return oops(compress, errno, "cannot stop the stream");
464 	return 0;
465 }
466 
compress_pause(struct compress * compress)467 int compress_pause(struct compress *compress)
468 {
469 	if (!is_compress_running(compress))
470 		return oops(compress, ENODEV, "device not ready");
471 	if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_PAUSE))
472 		return oops(compress, errno, "cannot pause the stream");
473 	return 0;
474 }
475 
compress_resume(struct compress * compress)476 int compress_resume(struct compress *compress)
477 {
478 	if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_RESUME))
479 		return oops(compress, errno, "cannot resume the stream");
480 	return 0;
481 }
482 
compress_drain(struct compress * compress)483 int compress_drain(struct compress *compress)
484 {
485 	if (!is_compress_running(compress))
486 		return oops(compress, ENODEV, "device not ready");
487 	if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_DRAIN))
488 		return oops(compress, errno, "cannot drain the stream");
489 	return 0;
490 }
491 
compress_partial_drain(struct compress * compress)492 int compress_partial_drain(struct compress *compress)
493 {
494 	if (!is_compress_running(compress))
495 		return oops(compress, ENODEV, "device not ready");
496 
497 	if (!compress->next_track)
498 		return oops(compress, EPERM, "next track not signalled");
499 	if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_PARTIAL_DRAIN))
500 		return oops(compress, errno, "cannot drain the stream\n");
501 	compress->next_track = 0;
502 	return 0;
503 }
504 
compress_next_track(struct compress * compress)505 int compress_next_track(struct compress *compress)
506 {
507 	if (!is_compress_running(compress))
508 		return oops(compress, ENODEV, "device not ready");
509 
510 	if (!compress->gapless_metadata)
511 		return oops(compress, EPERM, "metadata not set");
512 	if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_NEXT_TRACK))
513 		return oops(compress, errno, "cannot set next track\n");
514 	compress->next_track = 1;
515 	compress->gapless_metadata = 0;
516 	return 0;
517 }
518 
compress_set_gapless_metadata(struct compress * compress,struct compr_gapless_mdata * mdata)519 int 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))
526 		return oops(compress, ENODEV, "device not ready");
527 
528 	version = get_compress_version(compress);
529 	if (version <= 0)
530 		return -1;
531 
532 	if (version < SNDRV_PROTOCOL_VERSION(0, 1, 1))
533 		return oops(compress, ENXIO, "gapless apis not supported in kernel");
534 
535 	metadata.key = SNDRV_COMPRESS_ENCODER_PADDING;
536 	metadata.value[0] = mdata->encoder_padding;
537 	if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_SET_METADATA, &metadata))
538 		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;
542 	if (compress->ops->ioctl(compress->data, SNDRV_COMPRESS_SET_METADATA, &metadata))
543 		return oops(compress, errno, "can't set metadata for stream\n");
544 	compress->gapless_metadata = 1;
545 	return 0;
546 }
547 
548 #ifdef ENABLE_EXTENDED_COMPRESS_FORMAT
compress_set_next_track_param(struct compress * compress,union snd_codec_options * codec_options)549 int 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 
is_codec_supported(unsigned int card,unsigned int device,unsigned int flags,struct snd_codec * codec)561 bool is_codec_supported(unsigned int card, unsigned int device,
562 		unsigned int flags, struct snd_codec *codec)
563 {
564 	struct compress_ops *ops;
565 	void *snd_node, *data;
566 	bool ret;
567 	int compress_type, fd;
568 
569 	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;
573 	else
574 		ops = &compr_hw_ops;
575 
576 	fd = ops->open(card, device, flags, &data, NULL);
577 	if (fd < 0)
578 		return oops(&bad_compress, errno, "cannot open card %u, device %u",
579 					card, device);
580 
581 	ret = _is_codec_type_supported(ops, data, codec);
582 
583 	snd_utils_put_dev_node(snd_node);
584 	ops->close(data);
585 	return ret;
586 }
587 
compress_set_max_poll_wait(struct compress * compress,int milliseconds)588 void compress_set_max_poll_wait(struct compress *compress, int milliseconds)
589 {
590 	compress->max_poll_wait_ms = milliseconds;
591 }
592 
compress_nonblock(struct compress * compress,int nonblock)593 void compress_nonblock(struct compress *compress, int nonblock)
594 {
595 	compress->nonblocking = !!nonblock;
596 }
597 
compress_wait(struct compress * compress,int timeout_ms)598 int compress_wait(struct compress *compress, int timeout_ms)
599 {
600 	struct pollfd fds;
601 	int ret;
602 
603 	fds.events = POLLOUT | POLLIN;
604 
605 	ret = compress->ops->poll(compress->data, &fds, 1, timeout_ms);
606 	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;
611 	}
612 	if (ret == 0)
613 		return oops(compress, ETIME, "poll timed out");
614 	if (ret < 0)
615 		return oops(compress, errno, "poll error");
616 
617 	return oops(compress, EIO, "poll signalled unhandled event");
618 }
619 
620 #ifdef ENABLE_EXTENDED_COMPRESS_FORMAT
compress_get_metadata(struct compress * compress,struct snd_compr_metadata * mdata)621 int 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 
compress_set_metadata(struct compress * compress,struct snd_compr_metadata * mdata)637 int 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
654