1 /*
2  * A52 Output Plugin
3  *
4  * Copyright (c) 2006 by Takashi Iwai <tiwai@suse.de>
5  *
6  * This library is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 #include <stdio.h>
22 #include <string.h>
23 #define __USE_XOPEN
24 #include <unistd.h>
25 #include <alsa/asoundlib.h>
26 #include <alsa/pcm_external.h>
27 #include <alsa/pcm_plugin.h>
28 #include <libavcodec/avcodec.h>
29 #include <libavutil/avutil.h>
30 
31 /* some compatibility wrappers */
32 #ifndef AV_VERSION_INT
33 #define AV_VERSION_INT(a, b, c) (((a) << 16) | ((b) << 8) | (c))
34 #endif
35 #ifndef LIBAVCODEC_VERSION_INT
36 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
37                                                LIBAVCODEC_VERSION_MINOR, \
38                                                LIBAVCODEC_VERSION_MICRO)
39 #endif
40 
41 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 34, 0)
42 #include <libavutil/channel_layout.h>
43 #include <libavutil/mem.h>
44 #define USE_AVCODEC_FRAME
45 #endif
46 
47 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 0, 0)
48 #ifndef AV_CH_LAYOUT_STEREO
49 #define AV_CH_LAYOUT_STEREO	CH_LAYOUT_STEREO
50 #define AV_CH_LAYOUT_QUAD	CH_LAYOUT_QUAD
51 #define AV_CH_LAYOUT_5POINT1	CH_LAYOUT_5POINT1
52 #endif
53 #endif
54 
55 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(52, 95, 0)
56 #ifndef AV_SAMPLE_FMT_S16
57 #define AV_SAMPLE_FMT_S16	SAMPLE_FMT_S16
58 #endif
59 #endif
60 
61 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 25, 0)
62 #define AV_CODEC_ID_AC3 CODEC_ID_AC3
63 #endif
64 
65 #if LIBAVCODEC_VERSION_INT < 0x371c01
66 #define av_frame_alloc avcodec_alloc_frame
67 #define av_frame_free avcodec_free_frame
68 #endif
69 
70 struct a52_ctx {
71 	snd_pcm_ioplug_t io;
72 	snd_pcm_t *slave;
73 	AVCodec *codec;
74 	AVCodecContext *avctx;
75 	snd_pcm_format_t format;
76 	int av_format;
77 	unsigned int channels;
78 	unsigned int rate;
79 	unsigned int bitrate;
80 	short *inbuf;
81 	unsigned char *outbuf;
82 	int outbuf_size;
83 	snd_pcm_uframes_t transfer;
84 	int remain;
85 	int filled;
86 	unsigned int slave_period_size;
87 	unsigned int slave_buffer_size;
88 	snd_pcm_hw_params_t *hw_params;
89 #ifdef USE_AVCODEC_FRAME
90 	AVFrame *frame;
91 	int is_planar;
92 #endif
93 };
94 
95 #ifdef USE_AVCODEC_FRAME
96 #define use_planar(rec)		(rec)->is_planar
97 #else
98 #define use_planar(rec)		0
99 #endif
100 
101 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 34, 0)
do_encode(struct a52_ctx * rec)102 static int do_encode(struct a52_ctx *rec)
103 {
104 	AVPacket pkt = {
105 		.data = rec->outbuf + 8,
106 		.size = rec->outbuf_size - 8
107 	};
108 	int got_frame;
109 
110 	avcodec_encode_audio2(rec->avctx, &pkt, rec->frame, &got_frame);
111 	return pkt.size;
112 }
113 #else
do_encode(struct a52_ctx * rec)114 static int do_encode(struct a52_ctx *rec)
115 {
116 	return avcodec_encode_audio(rec->avctx, rec->outbuf + 8,
117 				    rec->outbuf_size - 8,
118 				    rec->inbuf);
119 }
120 #endif
121 
122 /* convert the PCM data to A52 stream in IEC958 */
convert_data(struct a52_ctx * rec)123 static void convert_data(struct a52_ctx *rec)
124 {
125 	int out_bytes = do_encode(rec);
126 
127 	rec->outbuf[0] = 0xf8; /* sync words */
128 	rec->outbuf[1] = 0x72;
129 	rec->outbuf[2] = 0x4e;
130 	rec->outbuf[3] = 0x1f;
131 	rec->outbuf[4] = rec->outbuf[13] & 7; /* bsmod */
132 	rec->outbuf[5] = 0x01; /* data type */
133 	rec->outbuf[6] = ((out_bytes * 8) >> 8) & 0xff;
134 	rec->outbuf[7] = (out_bytes * 8) & 0xff;
135 	/* swap bytes for little-endian 16bit */
136 	if (rec->format == SND_PCM_FORMAT_S16_LE)
137 		swab(rec->outbuf, rec->outbuf, out_bytes + 8);
138 	memset(rec->outbuf +  8 + out_bytes, 0,
139 	       rec->outbuf_size - 8 - out_bytes);
140 	rec->remain = rec->outbuf_size / 4;
141 	rec->filled = 0;
142 }
143 
144 /* write pending encoded data to the slave pcm */
write_out_pending(snd_pcm_ioplug_t * io,struct a52_ctx * rec)145 static int write_out_pending(snd_pcm_ioplug_t *io, struct a52_ctx *rec)
146 {
147 	int err, ofs = 0;
148 
149 	if (! rec->remain)
150 		return 0;
151 
152 	while (rec->remain) {
153 		err = snd_pcm_writei(rec->slave, rec->outbuf + ofs, rec->remain);
154 		if (err < 0) {
155 			if (err == -EPIPE)
156 				io->state = SND_PCM_STATE_XRUN;
157 			return err;
158 		} else if (! err)
159 			break;
160 		if (err < rec->remain)
161 			ofs += (rec->remain - err) * 4;
162 		rec->remain -= err;
163 	}
164 	if (rec->remain && ofs)
165 		memmove(rec->outbuf, rec->outbuf + ofs, rec->remain * 4);
166 	return 0;
167 }
168 
169 /*
170  * drain callback
171  */
172 #ifdef USE_AVCODEC_FRAME
clear_remaining_planar_data(snd_pcm_ioplug_t * io)173 static void clear_remaining_planar_data(snd_pcm_ioplug_t *io)
174 {
175 	struct a52_ctx *rec = io->private_data;
176 	unsigned int i;
177 
178 	for (i = 0; i < io->channels; i++)
179 		memset(rec->frame->data[i] + rec->filled * 2, 0,
180 		       (rec->avctx->frame_size - rec->filled) * 2);
181 }
182 #else
183 #define clear_remaining_planar_data(io) /*NOP*/
184 #endif
185 
a52_drain(snd_pcm_ioplug_t * io)186 static int a52_drain(snd_pcm_ioplug_t *io)
187 {
188 	struct a52_ctx *rec = io->private_data;
189 	int err;
190 
191 	if (rec->filled) {
192 		if ((err = write_out_pending(io, rec)) < 0)
193 			return err;
194 		/* remaining data must be converted and sent out */
195 		if (use_planar(rec))
196 			clear_remaining_planar_data(io);
197 		else {
198 			memset(rec->inbuf + rec->filled * io->channels, 0,
199 			       (rec->avctx->frame_size - rec->filled) * io->channels * 2);
200 		}
201 		convert_data(rec);
202 	}
203 	err = write_out_pending(io, rec);
204 	if (err < 0)
205 		return err;
206 
207 	return snd_pcm_drain(rec->slave);
208 }
209 
210 /* check whether the areas consist of a continuous interleaved stream */
check_interleaved(const snd_pcm_channel_area_t * areas,unsigned int channels)211 static int check_interleaved(const snd_pcm_channel_area_t *areas,
212 			     unsigned int channels)
213 {
214 	unsigned int ch;
215 
216 	if (channels > 4) /* we need re-routing for 6 channels */
217 		return 0;
218 
219 	for (ch = 0; ch < channels; ch++) {
220 		if (areas[ch].addr != areas[0].addr ||
221 		    areas[ch].first != ch * 16 ||
222 		    areas[ch].step != channels * 16)
223 			return 0;
224 	}
225 	return 1;
226 }
227 
228 /* Fill the input PCM to the internal buffer until a52 frames,
229  * then covert and write it out.
230  *
231  * Returns the number of processed frames.
232  */
fill_data(snd_pcm_ioplug_t * io,const snd_pcm_channel_area_t * areas,unsigned int offset,unsigned int size,int interleaved)233 static int fill_data(snd_pcm_ioplug_t *io,
234 		     const snd_pcm_channel_area_t *areas,
235 		     unsigned int offset, unsigned int size,
236 		     int interleaved)
237 {
238 	struct a52_ctx *rec = io->private_data;
239 	unsigned int len = rec->avctx->frame_size - rec->filled;
240 	short *src, *dst;
241 	unsigned int src_step;
242 	int err;
243 	static unsigned int ch_index[3][6] = {
244 		{ 0, 1 },
245 		{ 0, 1, 2, 3 },
246 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 26, 0)
247 		/* current libavcodec expects SMPTE order */
248 		{ 0, 1, 4, 5, 2, 3 },
249 #else
250 		/* libavcodec older than r18540 expects A52 order */
251 		{ 0, 4, 1, 2, 3, 5 },
252 #endif
253 	};
254 
255 	if ((err = write_out_pending(io, rec)) < 0)
256 		return err;
257 
258 	if (size > len)
259 		size = len;
260 
261 	dst = rec->inbuf + rec->filled * io->channels;
262 	if (!use_planar(rec) && interleaved) {
263 		memcpy(dst, areas->addr + offset * io->channels * 2,
264 		       size * io->channels * 2);
265 	} else {
266 		unsigned int i, ch, dst_step;
267 		short *dst1;
268 
269 		/* flatten copy to n-channel interleaved */
270 		dst_step = io->channels;
271 		for (ch = 0; ch < io->channels; ch++, dst++) {
272 			const snd_pcm_channel_area_t *ap;
273 			ap = &areas[ch_index[io->channels / 2 - 1][ch]];
274 			src = (short *)(ap->addr +
275 					(ap->first + offset * ap->step) / 8);
276 
277 #ifdef USE_AVCODEC_FRAME
278 			if (use_planar(rec)) {
279 				memcpy(rec->frame->data[ch], src, size * 2);
280 				continue;
281 			}
282 #endif
283 			dst1 = dst;
284 			src_step = ap->step / 16; /* in word */
285 			for (i = 0; i < size; i++) {
286 				*dst1 = *src;
287 				src += src_step;
288 				dst1 += dst_step;
289 			}
290 		}
291 	}
292 	rec->filled += size;
293 	if (rec->filled == rec->avctx->frame_size) {
294 		convert_data(rec);
295 		write_out_pending(io, rec);
296 	}
297 	return (int)size;
298 }
299 
300 /*
301  * transfer callback
302  */
a52_transfer(snd_pcm_ioplug_t * io,const snd_pcm_channel_area_t * areas,snd_pcm_uframes_t offset,snd_pcm_uframes_t size)303 static snd_pcm_sframes_t a52_transfer(snd_pcm_ioplug_t *io,
304 				      const snd_pcm_channel_area_t *areas,
305 				      snd_pcm_uframes_t offset,
306 				      snd_pcm_uframes_t size)
307 {
308 	struct a52_ctx *rec = io->private_data;
309 	snd_pcm_sframes_t result = 0;
310 	int err = 0;
311 	int interleaved = check_interleaved(areas, io->channels);
312 
313 	do {
314 		err = fill_data(io, areas, offset, size, interleaved);
315 		if (err < 0)
316 			break;
317 		offset += (unsigned int)err;
318 		size -= (unsigned int)err;
319 		result += err;
320 		rec->transfer += err;
321 	} while (size);
322 	return result > 0 ? result : err;
323 }
324 
325 /*
326  * pointer callback
327  *
328  * Calculate the current position from the delay of slave PCM
329  */
a52_pointer(snd_pcm_ioplug_t * io)330 static snd_pcm_sframes_t a52_pointer(snd_pcm_ioplug_t *io)
331 {
332 	struct a52_ctx *rec = io->private_data;
333 	snd_pcm_sframes_t delay;
334 	snd_pcm_state_t state;
335 	int err;
336 
337 	state = snd_pcm_state(rec->slave);
338 	switch (state) {
339 	case SND_PCM_STATE_RUNNING:
340 	case SND_PCM_STATE_DRAINING:
341 		if ((err = snd_pcm_delay(rec->slave, &delay)) < 0)
342 			return err;
343 		break;
344 	case SND_PCM_STATE_XRUN:
345 	case SND_PCM_STATE_SUSPENDED:
346 		return -EPIPE;
347 	default:
348 		return 0;
349 	}
350 
351 	if (delay < 0 || delay >= (snd_pcm_sframes_t)rec->slave_buffer_size)
352 		delay = 0;
353 	delay = (snd_pcm_sframes_t)io->appl_ptr - delay;
354 	if (delay < 0) {
355 		delay += io->buffer_size;
356 		if (delay < 0)
357 			delay = 0;
358 	}
359 	delay %= io->buffer_size;
360 	return delay;
361 }
362 
363 /* set up the fixed parameters of slave PCM hw_parmas */
a52_slave_hw_params_half(struct a52_ctx * rec)364 static int a52_slave_hw_params_half(struct a52_ctx *rec)
365 {
366 	int err;
367 
368 	if ((err = snd_pcm_hw_params_malloc(&rec->hw_params)) < 0)
369 		return err;
370 
371 	if ((err = snd_pcm_hw_params_any(rec->slave, rec->hw_params)) < 0) {
372 		SNDERR("Cannot get slave hw_params");
373 		goto out;
374 	}
375 	if ((err = snd_pcm_hw_params_set_access(rec->slave, rec->hw_params,
376 						SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
377 		SNDERR("Cannot set slave access RW_INTERLEAVED");
378 		goto out;
379 	}
380 	if ((err = snd_pcm_hw_params_set_channels(rec->slave, rec->hw_params, 2)) < 0) {
381 		SNDERR("Cannot set slave channels 2");
382 		goto out;
383 	}
384 	if ((err = snd_pcm_hw_params_set_format(rec->slave, rec->hw_params,
385 						rec->format)) < 0) {
386 		SNDERR("Cannot set slave format");
387 		goto out;
388 	}
389 	if ((err = snd_pcm_hw_params_set_rate(rec->slave, rec->hw_params, rec->rate, 0)) < 0) {
390 		SNDERR("Cannot set slave rate %d", rec->rate);
391 		goto out;
392 	}
393 	return 0;
394 
395  out:
396 	free(rec->hw_params);
397 	rec->hw_params = NULL;
398 	return err;
399 }
400 
401 /*
402  * hw_params callback
403  *
404  * Set up slave PCM according to the current parameters
405  */
a52_hw_params(snd_pcm_ioplug_t * io,snd_pcm_hw_params_t * params ATTRIBUTE_UNUSED)406 static int a52_hw_params(snd_pcm_ioplug_t *io,
407 			 snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED)
408 {
409 	struct a52_ctx *rec = io->private_data;
410 	snd_pcm_uframes_t period_size;
411 	snd_pcm_uframes_t buffer_size;
412 	int err;
413 
414 	if (! rec->hw_params) {
415 		err = a52_slave_hw_params_half(rec);
416 		if (err < 0)
417 			return err;
418 	}
419 	period_size = io->period_size;
420 	if ((err = snd_pcm_hw_params_set_period_size_near(rec->slave, rec->hw_params,
421 							  &period_size, NULL)) < 0) {
422 		SNDERR("Cannot set slave period size %ld", period_size);
423 		return err;
424 	}
425 	buffer_size = io->buffer_size;
426 	if ((err = snd_pcm_hw_params_set_buffer_size_near(rec->slave, rec->hw_params,
427 							  &buffer_size)) < 0) {
428 		SNDERR("Cannot set slave buffer size %ld", buffer_size);
429 		return err;
430 	}
431 	if ((err = snd_pcm_hw_params(rec->slave, rec->hw_params)) < 0) {
432 		SNDERR("Cannot set slave hw_params");
433 		return err;
434 	}
435 	rec->slave_period_size = period_size;
436 	rec->slave_buffer_size = buffer_size;
437 
438 	return 0;
439 }
440 
441 /*
442  * hw_free callback
443  */
a52_hw_free(snd_pcm_ioplug_t * io)444 static int a52_hw_free(snd_pcm_ioplug_t *io)
445 {
446 	struct a52_ctx *rec = io->private_data;
447 
448 	free(rec->hw_params);
449 	rec->hw_params = NULL;
450 	return snd_pcm_hw_free(rec->slave);
451 }
452 
453 /*
454  * sw_params callback
455  *
456  * Set up slave PCM sw_params
457  */
a52_sw_params(snd_pcm_ioplug_t * io,snd_pcm_sw_params_t * params)458 static int a52_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params)
459 {
460 	struct a52_ctx *rec = io->private_data;
461 	snd_pcm_sw_params_t *sparams;
462 	snd_pcm_uframes_t avail_min, start_threshold;
463 	int len;
464 
465 	snd_pcm_sw_params_get_avail_min(params, &avail_min);
466 	snd_pcm_sw_params_get_start_threshold(params, &start_threshold);
467 
468 	len = avail_min;
469 	len += (int)rec->slave_buffer_size - (int)io->buffer_size;
470 	if (len < 0)
471 		avail_min = 1;
472 	else
473 		avail_min = len;
474 	snd_pcm_sw_params_alloca(&sparams);
475 	snd_pcm_sw_params_current(rec->slave, sparams);
476 	snd_pcm_sw_params_set_avail_min(rec->slave, sparams, avail_min);
477 	snd_pcm_sw_params_set_start_threshold(rec->slave, sparams,
478 					      start_threshold);
479 
480 	return snd_pcm_sw_params(rec->slave, sparams);
481 }
482 
483 /*
484  * start and stop callbacks - just trigger slave PCM
485  */
a52_start(snd_pcm_ioplug_t * io)486 static int a52_start(snd_pcm_ioplug_t *io)
487 {
488 	struct a52_ctx *rec = io->private_data;
489 
490 	/* When trying to start a PCM that's already running, the result is
491 	   EBADFD. We might have implicitly started the buffer by filling it
492 	   up, so just ignore this request if we're already running. */
493 	if (snd_pcm_state(rec->slave) == SND_PCM_STATE_RUNNING)
494 		return 0;
495 
496 	return snd_pcm_start(rec->slave);
497 }
498 
a52_stop(snd_pcm_ioplug_t * io)499 static int a52_stop(snd_pcm_ioplug_t *io)
500 {
501 	struct a52_ctx *rec = io->private_data;
502 
503 	return snd_pcm_drop(rec->slave);
504 }
505 
506 /* release resources */
a52_free(struct a52_ctx * rec)507 static void a52_free(struct a52_ctx *rec)
508 {
509 	if (rec->avctx) {
510 		avcodec_close(rec->avctx);
511 		av_free(rec->avctx);
512 		rec->avctx = NULL;
513 	}
514 
515 #ifdef USE_AVCODEC_FRAME
516 	if (rec->frame) {
517 		av_freep(&rec->frame->data[0]);
518 		rec->inbuf = NULL;
519 	}
520 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
521 	av_frame_free(&rec->frame);
522 #else
523 	av_freep(&rec->frame);
524 #endif
525 #endif
526 
527 	free(rec->inbuf);
528 	rec->inbuf = NULL;
529 	free(rec->outbuf);
530 	rec->outbuf = NULL;
531 }
532 
533 /*
534  * prepare callback
535  *
536  * Allocate internal buffers and set up libavcodec
537  */
538 
539 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 3, 0)
set_channel_layout(snd_pcm_ioplug_t * io)540 static void set_channel_layout(snd_pcm_ioplug_t *io)
541 {
542 	struct a52_ctx *rec = io->private_data;
543 	switch (io->channels) {
544 	case 2:
545 		rec->avctx->channel_layout = AV_CH_LAYOUT_STEREO;
546 		break;
547 	case 4:
548 		rec->avctx->channel_layout = AV_CH_LAYOUT_QUAD;
549 		break;
550 	case 6:
551 		rec->avctx->channel_layout = AV_CH_LAYOUT_5POINT1;
552 		break;
553 	default:
554 		break;
555 	}
556 }
557 #else
558 #define set_channel_layout(io) /* NOP */
559 #endif
560 
alloc_input_buffer(snd_pcm_ioplug_t * io)561 static int alloc_input_buffer(snd_pcm_ioplug_t *io)
562 {
563 	struct a52_ctx *rec = io->private_data;
564 #ifdef USE_AVCODEC_FRAME
565 	rec->frame = av_frame_alloc();
566 	if (!rec->frame)
567 		return -ENOMEM;
568 	if (av_samples_alloc(rec->frame->data, rec->frame->linesize,
569 			     io->channels, rec->avctx->frame_size,
570 			     rec->avctx->sample_fmt, 0) < 0)
571 		return -ENOMEM;
572 	rec->frame->nb_samples = rec->avctx->frame_size;
573 	rec->inbuf = (short *)rec->frame->data[0];
574 #else
575 	rec->inbuf = malloc(rec->avctx->frame_size * 2 * io->channels);
576 #endif
577 	if (!rec->inbuf)
578 		return -ENOMEM;
579 	return 0;
580 }
581 
a52_prepare(snd_pcm_ioplug_t * io)582 static int a52_prepare(snd_pcm_ioplug_t *io)
583 {
584 	struct a52_ctx *rec = io->private_data;
585 	int err;
586 
587 	a52_free(rec);
588 
589 #ifdef USE_AVCODEC_FRAME
590 	rec->avctx = avcodec_alloc_context3(rec->codec);
591 #else
592 	rec->avctx = avcodec_alloc_context();
593 #endif
594 	if (!rec->avctx)
595 		return -ENOMEM;
596 
597 	rec->avctx->bit_rate = rec->bitrate * 1000;
598 	rec->avctx->sample_rate = io->rate;
599 	rec->avctx->channels = io->channels;
600 	rec->avctx->sample_fmt = rec->av_format;
601 
602 	set_channel_layout(io);
603 
604 
605 #ifdef USE_AVCODEC_FRAME
606 	err = avcodec_open2(rec->avctx, rec->codec, NULL);
607 #else
608 	err = avcodec_open(rec->avctx, rec->codec);
609 #endif
610 	if (err < 0)
611 		return -EINVAL;
612 
613 	rec->outbuf_size = rec->avctx->frame_size * 4;
614 	rec->outbuf = malloc(rec->outbuf_size);
615 	if (! rec->outbuf)
616 		return -ENOMEM;
617 
618 	if (alloc_input_buffer(io))
619 		return -ENOMEM;
620 
621 	rec->transfer = 0;
622 	rec->remain = 0;
623 	rec->filled = 0;
624 
625 	return snd_pcm_prepare(rec->slave);
626 }
627 
628 /*
629  * poll-related callbacks - just pass to slave PCM
630  */
a52_poll_descriptors_count(snd_pcm_ioplug_t * io)631 static int a52_poll_descriptors_count(snd_pcm_ioplug_t *io)
632 {
633 	struct a52_ctx *rec = io->private_data;
634 	return snd_pcm_poll_descriptors_count(rec->slave);
635 }
636 
a52_poll_descriptors(snd_pcm_ioplug_t * io,struct pollfd * pfd,unsigned int space)637 static int a52_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfd,
638 				unsigned int space)
639 {
640 	struct a52_ctx *rec = io->private_data;
641 	return snd_pcm_poll_descriptors(rec->slave, pfd, space);
642 }
643 
a52_poll_revents(snd_pcm_ioplug_t * io,struct pollfd * pfd,unsigned int nfds,unsigned short * revents)644 static int a52_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfd,
645 			    unsigned int nfds, unsigned short *revents)
646 {
647 	struct a52_ctx *rec = io->private_data;
648 	return snd_pcm_poll_descriptors_revents(rec->slave, pfd, nfds, revents);
649 }
650 
651 /*
652  * close callback
653  */
a52_close(snd_pcm_ioplug_t * io)654 static int a52_close(snd_pcm_ioplug_t *io)
655 {
656 	struct a52_ctx *rec = io->private_data;
657 	snd_pcm_t *slave = rec->slave;
658 
659 	a52_free(rec);
660 	if (slave) {
661 		rec->slave = NULL;
662 		return snd_pcm_close(slave);
663 	}
664 	return 0;
665 }
666 
667 #if SND_PCM_IOPLUG_VERSION >= 0x10002
668 static unsigned int chmap4[4] = {
669 	SND_CHMAP_FL, SND_CHMAP_FR,
670 	SND_CHMAP_RL, SND_CHMAP_RR,
671 };
672 static unsigned int chmap6[6] = {
673 	SND_CHMAP_FL, SND_CHMAP_FR,
674 	SND_CHMAP_RL, SND_CHMAP_RR,
675 	SND_CHMAP_FC, SND_CHMAP_LFE,
676 };
677 
a52_query_chmaps(snd_pcm_ioplug_t * io ATTRIBUTE_UNUSED)678 static snd_pcm_chmap_query_t **a52_query_chmaps(snd_pcm_ioplug_t *io ATTRIBUTE_UNUSED)
679 {
680 	snd_pcm_chmap_query_t **maps;
681 	int i;
682 
683 	maps = calloc(4, sizeof(void *));
684 	if (!maps)
685 		return NULL;
686 	for (i = 0; i < 3; i++) {
687 		snd_pcm_chmap_query_t *p;
688 		p = maps[i] = calloc((i + 1) * 2 + 2, sizeof(int));
689 		if (!p) {
690 			snd_pcm_free_chmaps(maps);
691 			return NULL;
692 		}
693 		p->type = SND_CHMAP_TYPE_FIXED;
694 		p->map.channels = (i + 1) * 2;
695 		memcpy(p->map.pos, i < 2 ? chmap4 : chmap6,
696 		       (i + 1) * 2 * sizeof(int));
697 	}
698 	return maps;
699 }
700 
a52_get_chmap(snd_pcm_ioplug_t * io)701 static snd_pcm_chmap_t *a52_get_chmap(snd_pcm_ioplug_t *io)
702 {
703 	snd_pcm_chmap_t *map;
704 
705 	if ((io->channels % 2) || io->channels < 2 || io->channels > 6)
706 		return NULL;
707 	map = malloc((io->channels + 1) * sizeof(int));
708 	if (!map)
709 		return NULL;
710 	map->channels = io->channels;
711 	memcpy(map->pos, io->channels < 6 ? chmap4 : chmap6,
712 	       io->channels * sizeof(int));
713 	return map;
714 }
715 #endif /* SND_PCM_IOPLUG_VERSION >= 0x10002 */
716 
717 /*
718  * callback table
719  */
720 static snd_pcm_ioplug_callback_t a52_ops = {
721 	.start = a52_start,
722 	.stop = a52_stop,
723 	.pointer = a52_pointer,
724 	.transfer = a52_transfer,
725 	.close = a52_close,
726 	.hw_params = a52_hw_params,
727 	.hw_free = a52_hw_free,
728 	.sw_params = a52_sw_params,
729 	.prepare = a52_prepare,
730 	.drain = a52_drain,
731 	.poll_descriptors_count = a52_poll_descriptors_count,
732 	.poll_descriptors = a52_poll_descriptors,
733 	.poll_revents = a52_poll_revents,
734 #if SND_PCM_IOPLUG_VERSION >= 0x10002
735 	.query_chmaps = a52_query_chmaps,
736 	.get_chmap = a52_get_chmap,
737 #endif /* SND_PCM_IOPLUG_VERSION >= 0x10002 */
738 };
739 
740 /*
741  * set up h/w constraints
742  *
743  * set the period size identical with A52 frame size.
744  * the max buffer size is calculated from the max buffer size
745  * of the slave PCM
746  */
747 
748 #define A52_FRAME_SIZE	1536
749 
750 #define ARRAY_SIZE(ary)	(sizeof(ary)/sizeof(ary[0]))
751 
a52_set_hw_constraint(struct a52_ctx * rec)752 static int a52_set_hw_constraint(struct a52_ctx *rec)
753 {
754 	static unsigned int accesses[] = {
755 		SND_PCM_ACCESS_MMAP_INTERLEAVED,
756 		SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
757 		SND_PCM_ACCESS_RW_INTERLEAVED,
758 		SND_PCM_ACCESS_RW_NONINTERLEAVED
759 	};
760 	static unsigned int accesses_planar[] = {
761 		SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
762 		SND_PCM_ACCESS_RW_NONINTERLEAVED
763 	};
764 	unsigned int formats[] = { SND_PCM_FORMAT_S16 };
765 	int err;
766 	snd_pcm_uframes_t buffer_max;
767 	unsigned int period_bytes, max_periods;
768 
769 	if (use_planar(rec))
770 		err = snd_pcm_ioplug_set_param_list(&rec->io,
771 						    SND_PCM_IOPLUG_HW_ACCESS,
772 						    ARRAY_SIZE(accesses_planar),
773 						    accesses_planar);
774 	else
775 		err = snd_pcm_ioplug_set_param_list(&rec->io,
776 						    SND_PCM_IOPLUG_HW_ACCESS,
777 						    ARRAY_SIZE(accesses),
778 						    accesses);
779 	if (err < 0)
780 		return err;
781 
782 	if ((err = snd_pcm_ioplug_set_param_list(&rec->io, SND_PCM_IOPLUG_HW_FORMAT,
783 						 ARRAY_SIZE(formats), formats)) < 0 ||
784 	    (err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_CHANNELS,
785 						   rec->channels, rec->channels)) < 0 ||
786 	    (err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_RATE,
787 						   rec->rate, rec->rate)) < 0)
788 		return err;
789 
790 	if ((err = a52_slave_hw_params_half(rec)) < 0)
791 		return err;
792 
793 	snd_pcm_hw_params_get_buffer_size_max(rec->hw_params, &buffer_max);
794 	period_bytes = A52_FRAME_SIZE * 2 * rec->channels;
795 	max_periods = buffer_max / A52_FRAME_SIZE;
796 
797 	if ((err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
798 						   period_bytes, period_bytes)) < 0 ||
799 	    (err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_PERIODS,
800 						   2, max_periods)) < 0)
801 		return err;
802 
803 	return 0;
804 }
805 
806 /*
807  * Main entry point
808  */
SND_PCM_PLUGIN_DEFINE_FUNC(a52)809 SND_PCM_PLUGIN_DEFINE_FUNC(a52)
810 {
811 	snd_config_iterator_t i, next;
812 	int err;
813 	const char *card = NULL;
814 	const char *pcm_string = NULL;
815 	unsigned int rate = 48000;
816 	unsigned int bitrate = 448;
817 	unsigned int channels = 6;
818 	snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
819 	char devstr[128], tmpcard[8];
820 	struct a52_ctx *rec;
821 
822 	if (stream != SND_PCM_STREAM_PLAYBACK) {
823 		SNDERR("a52 is only for playback");
824 		return -EINVAL;
825 	}
826 
827 	snd_config_for_each(i, next, conf) {
828 		snd_config_t *n = snd_config_iterator_entry(i);
829 		const char *id;
830 		if (snd_config_get_id(n, &id) < 0)
831 			continue;
832 		if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || strcmp(id, "hint") == 0)
833 			continue;
834 		if (strcmp(id, "card") == 0) {
835 			if (snd_config_get_string(n, &card) < 0) {
836 				long val;
837 				err = snd_config_get_integer(n, &val);
838 				if (err < 0) {
839 					SNDERR("Invalid type for %s", id);
840 					return -EINVAL;
841 				}
842 				snprintf(tmpcard, sizeof(tmpcard), "%ld", val);
843 				card = tmpcard;
844 			}
845 			continue;
846 		}
847 		if (strcmp(id, "slavepcm") == 0) {
848 			if (snd_config_get_string(n, &pcm_string) < 0) {
849 				SNDERR("a52 slavepcm must be a string");
850 				return -EINVAL;
851 			}
852 			continue;
853 		}
854 		if (strcmp(id, "rate") == 0) {
855 			long val;
856 			if (snd_config_get_integer(n, &val) < 0) {
857 				SNDERR("Invalid type for %s", id);
858 				return -EINVAL;
859 			}
860 			rate = val;
861 			if (rate != 44100 && rate != 48000) {
862 				SNDERR("rate must be 44100 or 48000");
863 				return -EINVAL;
864 			}
865 			continue;
866 		}
867 		if (strcmp(id, "bitrate") == 0) {
868 			long val;
869 			if (snd_config_get_integer(n, &val) < 0) {
870 				SNDERR("Invalid type for %s", id);
871 				return -EINVAL;
872 			}
873 			bitrate = val;
874 			if (bitrate < 128 || bitrate > 1000) {
875 				SNDERR("Invalid bitrate value %d", bitrate);
876 				return -EINVAL;
877 			}
878 			continue;
879 		}
880 		if (strcmp(id, "channels") == 0) {
881 			long val;
882 			if (snd_config_get_integer(n, &val) < 0) {
883 				SNDERR("Invalid type for %s", id);
884 				return -EINVAL;
885 			}
886 			channels = val;
887 			if (channels != 2 && channels != 4 && channels != 6) {
888 				SNDERR("channels must be 2, 4 or 6");
889 				return -EINVAL;
890 			}
891 			continue;
892 		}
893 		if (strcmp(id, "format") == 0) {
894 			const char *str;
895 			err = snd_config_get_string(n, &str);
896 			if (err < 0) {
897 				SNDERR("invalid type for %s", id);
898 				return -EINVAL;
899 			}
900 			format = snd_pcm_format_value(str);
901 			if (format == SND_PCM_FORMAT_UNKNOWN) {
902 				SNDERR("unknown format %s", str);
903 				return -EINVAL;
904 			}
905 			if (format != SND_PCM_FORMAT_S16_LE &&
906 			    format != SND_PCM_FORMAT_S16_BE) {
907 				SNDERR("Only S16_LE/BE formats are allowed");
908 				return -EINVAL;
909 			}
910 			continue;
911 		}
912 		SNDERR("Unknown field %s", id);
913 		return -EINVAL;
914 	}
915 
916 	rec = calloc(1, sizeof(*rec));
917 	if (! rec) {
918 		SNDERR("cannot allocate");
919 		return -ENOMEM;
920 	}
921 
922 	rec->rate = rate;
923 	rec->bitrate = bitrate;
924 	rec->channels = channels;
925 	rec->format = format;
926 
927 #ifndef USE_AVCODEC_FRAME
928 	avcodec_init();
929 #endif
930 	avcodec_register_all();
931 
932 	rec->codec = avcodec_find_encoder_by_name("ac3_fixed");
933 	if (rec->codec == NULL)
934 		rec->codec = avcodec_find_encoder_by_name("ac3");
935 	if (rec->codec == NULL)
936 		rec->codec = avcodec_find_encoder(AV_CODEC_ID_AC3);
937 	if (rec->codec == NULL) {
938 		SNDERR("Cannot find codec engine");
939 		err = -EINVAL;
940 		goto error;
941 	}
942 
943 	if (! pcm_string || pcm_string[0] == '\0') {
944 		snprintf(devstr, sizeof(devstr),
945 			 "iec958:{AES0 0x%x AES1 0x%x AES2 0x%x AES3 0x%x %s%s}",
946 			 IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO |
947 			 IEC958_AES0_CON_NOT_COPYRIGHT,
948 			 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
949 			 0, rate == 48000 ? IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100,
950 			 card ? " CARD " : "",
951 			 card ? card : "");
952 		err = snd_pcm_open(&rec->slave, devstr, stream, mode);
953 		if (err < 0)
954 			goto error;
955 		/* in case the slave doesn't support S16 format */
956 		err = snd_pcm_linear_open(&rec->slave, NULL, SND_PCM_FORMAT_S16,
957 					  rec->slave, 1);
958 		if (err < 0)
959 			goto error;
960 	} else {
961 		err = snd_pcm_open(&rec->slave, pcm_string, stream, mode);
962 		if (err < 0)
963 			goto error;
964 	}
965 
966 	rec->io.version = SND_PCM_IOPLUG_VERSION;
967 	rec->io.name = "A52 Output Plugin";
968 	rec->io.mmap_rw = 0;
969 	rec->io.callback = &a52_ops;
970 	rec->io.private_data = rec;
971 #ifdef USE_AVCODEC_FRAME
972 	rec->av_format = rec->codec->sample_fmts[0];
973 	rec->is_planar = av_sample_fmt_is_planar(rec->av_format);
974 #else
975 	rec->av_format = AV_SAMPLE_FMT_S16;
976 #endif
977 
978 	err = snd_pcm_ioplug_create(&rec->io, name, stream, mode);
979 	if (err < 0)
980 		goto error;
981 
982 	if ((err = a52_set_hw_constraint(rec)) < 0) {
983 		snd_pcm_ioplug_delete(&rec->io);
984 		goto error;
985 	}
986 
987 	*pcmp = rec->io.pcm;
988 	return 0;
989 
990  error:
991 	if (rec->slave)
992 		snd_pcm_close(rec->slave);
993 	free(rec);
994 	return err;
995 }
996 
997 SND_PCM_PLUGIN_SYMBOL(a52);
998