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