~ubuntu-branches/ubuntu/trusty/alsa-plugins/trusty

« back to all changes in this revision

Viewing changes to .pc/fix-ftbfs-libav9.patch/a52/pcm_a52.c

  • Committer: Package Import Robot
  • Author(s): Luke Yelavich
  • Date: 2013-07-26 10:57:49 UTC
  • mfrom: (3.1.16 sid)
  • Revision ID: package-import@ubuntu.com-20130726105749-ymn7cpbi75gmgplw
Tags: 1.0.27-2ubuntu1
* Merge from debian unstable, remaining changes:
  - Create libasound2-plugins-extra package which contains plugins that use
    libav.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 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 AVCODEC_HEADER
29
 
#include <libavutil/avutil.h>
30
 
 
31
 
struct a52_ctx {
32
 
        snd_pcm_ioplug_t io;
33
 
        snd_pcm_t *slave;
34
 
        AVCodec *codec;
35
 
        AVCodecContext *avctx;
36
 
        snd_pcm_format_t format;
37
 
        unsigned int channels;
38
 
        unsigned int rate;
39
 
        unsigned int bitrate;
40
 
        short *inbuf;
41
 
        unsigned char *outbuf;
42
 
        int outbuf_size;
43
 
        snd_pcm_uframes_t transfer;
44
 
        int remain;
45
 
        int filled;
46
 
        unsigned int slave_period_size;
47
 
        unsigned int slave_buffer_size;
48
 
        snd_pcm_hw_params_t *hw_params;
49
 
};
50
 
 
51
 
/* convert the PCM data to A52 stream in IEC958 */
52
 
static void convert_data(struct a52_ctx *rec)
53
 
{
54
 
        int out_bytes;
55
 
 
56
 
        out_bytes = avcodec_encode_audio(rec->avctx, rec->outbuf + 8,
57
 
                                         rec->outbuf_size - 8,
58
 
                                         rec->inbuf);
59
 
        rec->outbuf[0] = 0xf8; /* sync words */
60
 
        rec->outbuf[1] = 0x72;
61
 
        rec->outbuf[2] = 0x4e;
62
 
        rec->outbuf[3] = 0x1f;
63
 
        rec->outbuf[4] = rec->outbuf[13] & 7; /* bsmod */
64
 
        rec->outbuf[5] = 0x01; /* data type */
65
 
        rec->outbuf[6] = ((out_bytes * 8) >> 8) & 0xff;
66
 
        rec->outbuf[7] = (out_bytes * 8) & 0xff;
67
 
        /* swap bytes for little-endian 16bit */
68
 
        if (rec->format == SND_PCM_FORMAT_S16_LE)
69
 
                swab(rec->outbuf, rec->outbuf, out_bytes + 8);
70
 
        memset(rec->outbuf +  8 + out_bytes, 0,
71
 
               rec->outbuf_size - 8 - out_bytes);
72
 
        rec->remain = rec->outbuf_size / 4;
73
 
        rec->filled = 0;
74
 
}
75
 
 
76
 
/* write pending encoded data to the slave pcm */
77
 
static int write_out_pending(snd_pcm_ioplug_t *io, struct a52_ctx *rec)
78
 
{
79
 
        int err, ofs = 0;
80
 
 
81
 
        if (! rec->remain)
82
 
                return 0;
83
 
 
84
 
        while (rec->remain) {
85
 
                err = snd_pcm_writei(rec->slave, rec->outbuf + ofs, rec->remain);
86
 
                if (err < 0) {
87
 
                        if (err == -EPIPE)
88
 
                                io->state = SND_PCM_STATE_XRUN;
89
 
                        return err;
90
 
                } else if (! err)
91
 
                        break;
92
 
                if (err < rec->remain)
93
 
                        ofs += (rec->remain - err) * 4;
94
 
                rec->remain -= err;
95
 
        }
96
 
        if (rec->remain && ofs)
97
 
                memmove(rec->outbuf, rec->outbuf + ofs, rec->remain * 4);
98
 
        return 0;
99
 
}
100
 
 
101
 
/*
102
 
 * drain callback
103
 
 */
104
 
static int a52_drain(snd_pcm_ioplug_t *io)
105
 
{
106
 
        struct a52_ctx *rec = io->private_data;
107
 
        int err;
108
 
 
109
 
        if (rec->filled) {
110
 
                if ((err = write_out_pending(io, rec)) < 0)
111
 
                        return err;
112
 
                /* remaining data must be converted and sent out */
113
 
                memset(rec->inbuf + rec->filled * io->channels, 0,
114
 
                       (rec->avctx->frame_size - rec->filled) * io->channels * 2);
115
 
                convert_data(rec);
116
 
        }
117
 
        err = write_out_pending(io, rec);
118
 
        if (err < 0)
119
 
                return err;
120
 
        snd_pcm_drain(rec->slave);
121
 
        return 0;
122
 
}
123
 
 
124
 
/* check whether the areas consist of a continuous interleaved stream */
125
 
static int check_interleaved(const snd_pcm_channel_area_t *areas,
126
 
                             unsigned int channels)
127
 
{
128
 
        unsigned int ch;
129
 
 
130
 
        if (channels > 4) /* we need re-routing for 6 channels */
131
 
                return 0;
132
 
 
133
 
        for (ch = 0; ch < channels; ch++) {
134
 
                if (areas[ch].addr != areas[0].addr ||
135
 
                    areas[ch].first != ch * 16 ||
136
 
                    areas[ch].step != channels * 16)
137
 
                        return 0;
138
 
        }
139
 
        return 1;
140
 
}
141
 
 
142
 
/* Fill the input PCM to the internal buffer until a52 frames,
143
 
 * then covert and write it out.
144
 
 *
145
 
 * Returns the number of processed frames.
146
 
 */
147
 
static int fill_data(snd_pcm_ioplug_t *io,
148
 
                     const snd_pcm_channel_area_t *areas,
149
 
                     unsigned int offset, unsigned int size,
150
 
                     int interleaved)
151
 
{
152
 
        struct a52_ctx *rec = io->private_data;
153
 
        unsigned int len = rec->avctx->frame_size - rec->filled;
154
 
        short *src, *dst;
155
 
        unsigned int src_step;
156
 
        int err;
157
 
 
158
 
        if ((err = write_out_pending(io, rec)) < 0)
159
 
                return err;
160
 
 
161
 
        if (size > len)
162
 
                size = len;
163
 
 
164
 
        dst = rec->inbuf + rec->filled * io->channels;
165
 
        if (interleaved) {
166
 
                memcpy(dst, areas->addr + offset * io->channels * 2,
167
 
                       size * io->channels * 2);
168
 
        } else {
169
 
                unsigned int i, ch, dst_step;
170
 
                short *dst1;
171
 
                static unsigned int ch_index[3][6] = {
172
 
                        { 0, 1 },
173
 
                        { 0, 1, 2, 3 },
174
 
#if LIBAVCODEC_VERSION_MAJOR > 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 26)
175
 
                        /* current libavcodec expects SMPTE order */
176
 
                        { 0, 1, 4, 5, 2, 3 },
177
 
#else
178
 
                        /* libavcodec older than r18540 expects A52 order */
179
 
                        { 0, 4, 1, 2, 3, 5 },
180
 
#endif
181
 
                };
182
 
                /* flatten copy to n-channel interleaved */
183
 
                dst_step = io->channels;
184
 
                for (ch = 0; ch < io->channels; ch++, dst++) {
185
 
                        const snd_pcm_channel_area_t *ap;
186
 
                        ap = &areas[ch_index[io->channels / 2 - 1][ch]];
187
 
                        dst1 = dst;
188
 
                        src = (short *)(ap->addr +
189
 
                                        (ap->first + offset * ap->step) / 8);
190
 
                        src_step = ap->step / 16; /* in word */
191
 
                        for (i = 0; i < size; i++) {
192
 
                                *dst1 = *src;
193
 
                                src += src_step;
194
 
                                dst1 += dst_step;
195
 
                        }
196
 
                }
197
 
        }
198
 
        rec->filled += size;
199
 
        if (rec->filled == rec->avctx->frame_size) {
200
 
                convert_data(rec);
201
 
                write_out_pending(io, rec);
202
 
        }
203
 
        return (int)size;
204
 
}
205
 
 
206
 
/*
207
 
 * transfer callback
208
 
 */
209
 
static snd_pcm_sframes_t a52_transfer(snd_pcm_ioplug_t *io,
210
 
                                      const snd_pcm_channel_area_t *areas,
211
 
                                      snd_pcm_uframes_t offset,
212
 
                                      snd_pcm_uframes_t size)
213
 
{
214
 
        struct a52_ctx *rec = io->private_data;
215
 
        snd_pcm_sframes_t result = 0;
216
 
        int err = 0;
217
 
        int interleaved = check_interleaved(areas, io->channels);
218
 
 
219
 
        do {
220
 
                err = fill_data(io, areas, offset, size, interleaved);
221
 
                if (err < 0)
222
 
                        break;
223
 
                offset += (unsigned int)err;
224
 
                size -= (unsigned int)err;
225
 
                result += err;
226
 
                rec->transfer += err;
227
 
        } while (size);
228
 
        return result > 0 ? result : err;
229
 
}
230
 
 
231
 
/*
232
 
 * pointer callback
233
 
 *
234
 
 * Calculate the current position from the delay of slave PCM
235
 
 */
236
 
static snd_pcm_sframes_t a52_pointer(snd_pcm_ioplug_t *io)
237
 
{
238
 
        struct a52_ctx *rec = io->private_data;
239
 
        snd_pcm_sframes_t delay;
240
 
        snd_pcm_state_t state;
241
 
        int err;
242
 
 
243
 
        state = snd_pcm_state(rec->slave);
244
 
        switch (state) {
245
 
        case SND_PCM_STATE_RUNNING:
246
 
        case SND_PCM_STATE_DRAINING:
247
 
                if ((err = snd_pcm_delay(rec->slave, &delay)) < 0)
248
 
                        return err;
249
 
                break;
250
 
        case SND_PCM_STATE_XRUN:
251
 
        case SND_PCM_STATE_SUSPENDED:
252
 
                return -EPIPE;
253
 
        default:
254
 
                return 0;
255
 
        }
256
 
 
257
 
        if (delay < 0 || delay >= (snd_pcm_sframes_t)rec->slave_buffer_size)
258
 
                delay = 0;
259
 
        delay = (snd_pcm_sframes_t)io->appl_ptr - delay;
260
 
        if (delay < 0) {
261
 
                delay += io->buffer_size;
262
 
                if (delay < 0)
263
 
                        delay = 0;
264
 
        }
265
 
        delay %= io->buffer_size;
266
 
        return delay;
267
 
}
268
 
 
269
 
/* set up the fixed parameters of slave PCM hw_parmas */
270
 
static int a52_slave_hw_params_half(struct a52_ctx *rec)
271
 
{
272
 
        int err;
273
 
 
274
 
        if ((err = snd_pcm_hw_params_malloc(&rec->hw_params)) < 0)
275
 
                return err;
276
 
 
277
 
        if ((err = snd_pcm_hw_params_any(rec->slave, rec->hw_params)) < 0) {
278
 
                SNDERR("Cannot get slave hw_params");
279
 
                goto out;
280
 
        }
281
 
        if ((err = snd_pcm_hw_params_set_access(rec->slave, rec->hw_params,
282
 
                                                SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
283
 
                SNDERR("Cannot set slave access RW_INTERLEAVED");
284
 
                goto out;
285
 
        }
286
 
        if ((err = snd_pcm_hw_params_set_channels(rec->slave, rec->hw_params, 2)) < 0) {
287
 
                SNDERR("Cannot set slave channels 2");
288
 
                goto out;
289
 
        }
290
 
        if ((err = snd_pcm_hw_params_set_format(rec->slave, rec->hw_params,
291
 
                                                rec->format)) < 0) {
292
 
                SNDERR("Cannot set slave format");
293
 
                goto out;
294
 
        }
295
 
        if ((err = snd_pcm_hw_params_set_rate(rec->slave, rec->hw_params, rec->rate, 0)) < 0) {
296
 
                SNDERR("Cannot set slave rate %d", rec->rate);
297
 
                goto out;
298
 
        }
299
 
        return 0;
300
 
 
301
 
 out:
302
 
        free(rec->hw_params);
303
 
        rec->hw_params = NULL;
304
 
        return err;
305
 
}
306
 
 
307
 
/*
308
 
 * hw_params callback
309
 
 *
310
 
 * Set up slave PCM according to the current parameters
311
 
 */
312
 
static int a52_hw_params(snd_pcm_ioplug_t *io,
313
 
                         snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED)
314
 
{
315
 
        struct a52_ctx *rec = io->private_data;
316
 
        snd_pcm_uframes_t period_size;
317
 
        snd_pcm_uframes_t buffer_size;
318
 
        int err;
319
 
 
320
 
        if (! rec->hw_params) {
321
 
                err = a52_slave_hw_params_half(rec);
322
 
                if (err < 0)
323
 
                        return err;
324
 
        }
325
 
        period_size = io->period_size;
326
 
        if ((err = snd_pcm_hw_params_set_period_size_near(rec->slave, rec->hw_params,
327
 
                                                          &period_size, NULL)) < 0) {
328
 
                SNDERR("Cannot set slave period size %ld", period_size);
329
 
                return err;
330
 
        }
331
 
        buffer_size = io->buffer_size;
332
 
        if ((err = snd_pcm_hw_params_set_buffer_size_near(rec->slave, rec->hw_params,
333
 
                                                          &buffer_size)) < 0) {
334
 
                SNDERR("Cannot set slave buffer size %ld", buffer_size);
335
 
                return err;
336
 
        }
337
 
        if ((err = snd_pcm_hw_params(rec->slave, rec->hw_params)) < 0) {
338
 
                SNDERR("Cannot set slave hw_params");
339
 
                return err;
340
 
        }
341
 
        rec->slave_period_size = period_size;
342
 
        rec->slave_buffer_size = buffer_size;
343
 
 
344
 
        return 0;
345
 
}
346
 
 
347
 
/*
348
 
 * hw_free callback
349
 
 */
350
 
static int a52_hw_free(snd_pcm_ioplug_t *io)
351
 
{
352
 
        struct a52_ctx *rec = io->private_data;
353
 
 
354
 
        free(rec->hw_params);
355
 
        rec->hw_params = NULL;
356
 
        return snd_pcm_hw_free(rec->slave);
357
 
}
358
 
 
359
 
/*
360
 
 * sw_params callback
361
 
 *
362
 
 * Set up slave PCM sw_params
363
 
 */
364
 
static int a52_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t *params)
365
 
{
366
 
        struct a52_ctx *rec = io->private_data;
367
 
        snd_pcm_sw_params_t *sparams;
368
 
        snd_pcm_uframes_t avail_min, start_threshold;
369
 
        int len;
370
 
 
371
 
        snd_pcm_sw_params_get_avail_min(params, &avail_min);
372
 
        snd_pcm_sw_params_get_start_threshold(params, &start_threshold);
373
 
 
374
 
        len = avail_min;
375
 
        len += (int)rec->slave_buffer_size - (int)io->buffer_size;
376
 
        if (len < 0)
377
 
                avail_min = 1;
378
 
        else
379
 
                avail_min = len;
380
 
        snd_pcm_sw_params_alloca(&sparams);
381
 
        snd_pcm_sw_params_current(rec->slave, sparams);
382
 
        snd_pcm_sw_params_set_avail_min(rec->slave, sparams, avail_min);
383
 
        snd_pcm_sw_params_set_start_threshold(rec->slave, sparams,
384
 
                                              start_threshold);
385
 
 
386
 
        return snd_pcm_sw_params(rec->slave, sparams);
387
 
}
388
 
 
389
 
/*
390
 
 * start and stop callbacks - just trigger slave PCM
391
 
 */
392
 
static int a52_start(snd_pcm_ioplug_t *io)
393
 
{
394
 
        struct a52_ctx *rec = io->private_data;
395
 
 
396
 
        snd_pcm_start(rec->slave);
397
 
        return 0;
398
 
}
399
 
 
400
 
static int a52_stop(snd_pcm_ioplug_t *io)
401
 
{
402
 
        struct a52_ctx *rec = io->private_data;
403
 
 
404
 
        snd_pcm_drop(rec->slave);
405
 
        return 0;
406
 
}
407
 
 
408
 
/* release resources */
409
 
static void a52_free(struct a52_ctx *rec)
410
 
{
411
 
        if (rec->avctx) {
412
 
                avcodec_close(rec->avctx);
413
 
                av_free(rec->avctx);
414
 
                rec->avctx = NULL;
415
 
        }
416
 
        free(rec->inbuf);
417
 
        rec->inbuf = NULL;
418
 
        free(rec->outbuf);
419
 
        rec->outbuf = NULL;
420
 
}
421
 
 
422
 
/*
423
 
 * prepare callback
424
 
 *
425
 
 * Allocate internal buffers and set up libavcodec
426
 
 */
427
 
static int a52_prepare(snd_pcm_ioplug_t *io)
428
 
{
429
 
        struct a52_ctx *rec = io->private_data;
430
 
 
431
 
        a52_free(rec);
432
 
 
433
 
        rec->avctx = avcodec_alloc_context();
434
 
        if (! rec->avctx)
435
 
                return -ENOMEM;
436
 
 
437
 
        rec->avctx->bit_rate = rec->bitrate * 1000;
438
 
        rec->avctx->sample_rate = io->rate;
439
 
        rec->avctx->channels = io->channels;
440
 
#if LIBAVCODEC_VERSION_MAJOR > 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 95)
441
 
  rec->avctx->sample_fmt = AV_SAMPLE_FMT_S16;
442
 
#else
443
 
  rec->avctx->sample_fmt = SAMPLE_FMT_S16;
444
 
#endif
445
 
#if LIBAVCODEC_VERSION_MAJOR > 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR >= 3)
446
 
        switch (io->channels) {
447
 
        case 2:
448
 
                rec->avctx->channel_layout = CH_LAYOUT_STEREO;
449
 
                break;
450
 
        case 4:
451
 
                rec->avctx->channel_layout = CH_LAYOUT_QUAD;
452
 
                break;
453
 
        case 6:
454
 
                rec->avctx->channel_layout = CH_LAYOUT_5POINT1;
455
 
                break;
456
 
        default:
457
 
                break;
458
 
        }
459
 
#endif
460
 
 
461
 
        if (avcodec_open(rec->avctx, rec->codec) < 0)
462
 
                return -EINVAL;
463
 
 
464
 
        rec->inbuf = malloc(rec->avctx->frame_size * 2 * io->channels);
465
 
        if (! rec->inbuf)
466
 
                return -ENOMEM;
467
 
        rec->outbuf_size = rec->avctx->frame_size * 4;
468
 
        rec->outbuf = malloc(rec->outbuf_size);
469
 
        if (! rec->outbuf)
470
 
                return -ENOMEM;
471
 
 
472
 
        rec->transfer = 0;
473
 
        rec->remain = 0;
474
 
        rec->filled = 0;
475
 
 
476
 
        return snd_pcm_prepare(rec->slave);
477
 
}
478
 
 
479
 
/*
480
 
 * poll-related callbacks - just pass to slave PCM
481
 
 */
482
 
static int a52_poll_descriptors_count(snd_pcm_ioplug_t *io)
483
 
{
484
 
        struct a52_ctx *rec = io->private_data;
485
 
        return snd_pcm_poll_descriptors_count(rec->slave);
486
 
}
487
 
 
488
 
static int a52_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfd,
489
 
                                unsigned int space)
490
 
{
491
 
        struct a52_ctx *rec = io->private_data;
492
 
        return snd_pcm_poll_descriptors(rec->slave, pfd, space);
493
 
}
494
 
 
495
 
static int a52_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfd,
496
 
                            unsigned int nfds, unsigned short *revents)
497
 
{
498
 
        struct a52_ctx *rec = io->private_data;
499
 
        return snd_pcm_poll_descriptors_revents(rec->slave, pfd, nfds, revents);
500
 
}
501
 
 
502
 
/*
503
 
 * close callback
504
 
 */
505
 
static int a52_close(snd_pcm_ioplug_t *io)
506
 
{
507
 
        struct a52_ctx *rec = io->private_data;
508
 
 
509
 
        a52_free(rec);
510
 
        if (rec->slave)
511
 
                snd_pcm_close(rec->slave);
512
 
        return 0;
513
 
}
514
 
                              
515
 
/*
516
 
 * callback table
517
 
 */
518
 
static snd_pcm_ioplug_callback_t a52_ops = {
519
 
        .start = a52_start,
520
 
        .stop = a52_stop,
521
 
        .pointer = a52_pointer,
522
 
        .transfer = a52_transfer,
523
 
        .close = a52_close,
524
 
        .hw_params = a52_hw_params,
525
 
        .hw_free = a52_hw_free,
526
 
        .sw_params = a52_sw_params,
527
 
        .prepare = a52_prepare,
528
 
        .drain = a52_drain,
529
 
        .poll_descriptors_count = a52_poll_descriptors_count,
530
 
        .poll_descriptors = a52_poll_descriptors,
531
 
        .poll_revents = a52_poll_revents,
532
 
};
533
 
 
534
 
/*
535
 
 * set up h/w constraints
536
 
 *
537
 
 * set the period size identical with A52 frame size.
538
 
 * the max buffer size is calculated from the max buffer size
539
 
 * of the slave PCM
540
 
 */
541
 
 
542
 
#define A52_FRAME_SIZE  1536
543
 
 
544
 
#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0]))
545
 
 
546
 
static int a52_set_hw_constraint(struct a52_ctx *rec)
547
 
{
548
 
        unsigned int accesses[] = {
549
 
                SND_PCM_ACCESS_MMAP_INTERLEAVED,
550
 
                SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
551
 
                SND_PCM_ACCESS_RW_INTERLEAVED,
552
 
                SND_PCM_ACCESS_RW_NONINTERLEAVED
553
 
        };
554
 
        unsigned int formats[] = { SND_PCM_FORMAT_S16 };
555
 
        int err;
556
 
        snd_pcm_uframes_t buffer_max;
557
 
        unsigned int period_bytes, max_periods;
558
 
 
559
 
        if ((err = snd_pcm_ioplug_set_param_list(&rec->io, SND_PCM_IOPLUG_HW_ACCESS,
560
 
                                                 ARRAY_SIZE(accesses), accesses)) < 0 ||
561
 
            (err = snd_pcm_ioplug_set_param_list(&rec->io, SND_PCM_IOPLUG_HW_FORMAT,
562
 
                                                 ARRAY_SIZE(formats), formats)) < 0 ||
563
 
            (err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_CHANNELS,
564
 
                                                   rec->channels, rec->channels)) < 0 ||
565
 
            (err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_RATE,
566
 
                                                   rec->rate, rec->rate)) < 0)
567
 
                return err;
568
 
 
569
 
        if ((err = a52_slave_hw_params_half(rec)) < 0)
570
 
                return err;
571
 
 
572
 
        snd_pcm_hw_params_get_buffer_size_max(rec->hw_params, &buffer_max);
573
 
        period_bytes = A52_FRAME_SIZE * 2 * rec->channels;
574
 
        max_periods = buffer_max / A52_FRAME_SIZE;
575
 
 
576
 
        if ((err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
577
 
                                                   period_bytes, period_bytes)) < 0 ||
578
 
            (err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_PERIODS,
579
 
                                                   2, max_periods)) < 0)
580
 
                return err;
581
 
 
582
 
        return 0;
583
 
}
584
 
 
585
 
/*
586
 
 * Main entry point
587
 
 */
588
 
SND_PCM_PLUGIN_DEFINE_FUNC(a52)
589
 
{
590
 
        snd_config_iterator_t i, next;
591
 
        int err;
592
 
        const char *card = NULL;
593
 
        const char *pcm_string = NULL;
594
 
        unsigned int rate = 48000;
595
 
        unsigned int bitrate = 448;
596
 
        unsigned int channels = 6;
597
 
        snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
598
 
        char devstr[128], tmpcard[8];
599
 
        struct a52_ctx *rec;
600
 
        
601
 
        if (stream != SND_PCM_STREAM_PLAYBACK) {
602
 
                SNDERR("a52 is only for playback");
603
 
                return -EINVAL;
604
 
        }
605
 
 
606
 
        snd_config_for_each(i, next, conf) {
607
 
                snd_config_t *n = snd_config_iterator_entry(i);
608
 
                const char *id;
609
 
                if (snd_config_get_id(n, &id) < 0)
610
 
                        continue;
611
 
                if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || strcmp(id, "hint") == 0)
612
 
                        continue;
613
 
                if (strcmp(id, "card") == 0) {
614
 
                        if (snd_config_get_string(n, &card) < 0) {
615
 
                                long val;
616
 
                                err = snd_config_get_integer(n, &val);
617
 
                                if (err < 0) {
618
 
                                        SNDERR("Invalid type for %s", id);
619
 
                                        return -EINVAL;
620
 
                                }
621
 
                                snprintf(tmpcard, sizeof(tmpcard), "%ld", val);
622
 
                                card = tmpcard;
623
 
                        }
624
 
                        continue;
625
 
                }
626
 
                if (strcmp(id, "slavepcm") == 0) {
627
 
                        if (snd_config_get_string(n, &pcm_string) < 0) {
628
 
                                SNDERR("a52 slavepcm must be a string");
629
 
                                return -EINVAL;
630
 
                        }
631
 
                        continue;
632
 
                }
633
 
                if (strcmp(id, "rate") == 0) {
634
 
                        long val;
635
 
                        if (snd_config_get_integer(n, &val) < 0) {
636
 
                                SNDERR("Invalid type for %s", id);
637
 
                                return -EINVAL;
638
 
                        }
639
 
                        rate = val;
640
 
                        if (rate != 44100 && rate != 48000) {
641
 
                                SNDERR("rate must be 44100 or 48000");
642
 
                                return -EINVAL;
643
 
                        }
644
 
                        continue;
645
 
                }
646
 
                if (strcmp(id, "bitrate") == 0) {
647
 
                        long val;
648
 
                        if (snd_config_get_integer(n, &val) < 0) {
649
 
                                SNDERR("Invalid type for %s", id);
650
 
                                return -EINVAL;
651
 
                        }
652
 
                        bitrate = val;
653
 
                        if (bitrate < 128 || bitrate > 1000) {
654
 
                                SNDERR("Invalid bitrate value %d", bitrate);
655
 
                                return -EINVAL;
656
 
                        }
657
 
                        continue;
658
 
                }
659
 
                if (strcmp(id, "channels") == 0) {
660
 
                        long val;
661
 
                        if (snd_config_get_integer(n, &val) < 0) {
662
 
                                SNDERR("Invalid type for %s", id);
663
 
                                return -EINVAL;
664
 
                        }
665
 
                        channels = val;
666
 
                        if (channels != 2 && channels != 4 && channels != 6) {
667
 
                                SNDERR("channels must be 2, 4 or 6");
668
 
                                return -EINVAL;
669
 
                        }
670
 
                        continue;
671
 
                }
672
 
                if (strcmp(id, "format") == 0) {
673
 
                        const char *str;
674
 
                        err = snd_config_get_string(n, &str);
675
 
                        if (err < 0) {
676
 
                                SNDERR("invalid type for %s", id);
677
 
                                return -EINVAL;
678
 
                        }
679
 
                        format = snd_pcm_format_value(str);
680
 
                        if (format == SND_PCM_FORMAT_UNKNOWN) {
681
 
                                SNDERR("unknown format %s", str);
682
 
                                return -EINVAL;
683
 
                        }
684
 
                        if (format != SND_PCM_FORMAT_S16_LE &&
685
 
                            format != SND_PCM_FORMAT_S16_BE) {
686
 
                                SNDERR("Only S16_LE/BE formats are allowed");
687
 
                                return -EINVAL;
688
 
                        }
689
 
                        continue;
690
 
                }
691
 
                SNDERR("Unknown field %s", id);
692
 
                return -EINVAL;
693
 
        }
694
 
 
695
 
        rec = calloc(1, sizeof(*rec));
696
 
        if (! rec) {
697
 
                SNDERR("cannot allocate");
698
 
                return -ENOMEM;
699
 
        }
700
 
 
701
 
        rec->rate = rate;
702
 
        rec->bitrate = bitrate;
703
 
        rec->channels = channels;
704
 
        rec->format = format;
705
 
 
706
 
        avcodec_init();
707
 
        avcodec_register_all();
708
 
 
709
 
        rec->codec = avcodec_find_encoder_by_name("ac3_fixed");
710
 
        if (rec->codec == NULL)
711
 
                rec->codec = avcodec_find_encoder_by_name("ac3");
712
 
        if (rec->codec == NULL) 
713
 
                rec->codec = avcodec_find_encoder(CODEC_ID_AC3);
714
 
        if (rec->codec == NULL) {
715
 
                SNDERR("Cannot find codec engine");
716
 
                err = -EINVAL;
717
 
                goto error;
718
 
        }
719
 
 
720
 
        if (! pcm_string) {
721
 
                snprintf(devstr, sizeof(devstr),
722
 
                         "iec958:{AES0 0x%x AES1 0x%x AES2 0x%x AES3 0x%x %s%s}",
723
 
                         IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO |
724
 
                         IEC958_AES0_CON_NOT_COPYRIGHT,
725
 
                         IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
726
 
                         0, rate == 48000 ? IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100,
727
 
                         card ? " CARD " : "",
728
 
                         card ? card : "");
729
 
                err = snd_pcm_open(&rec->slave, devstr, stream, mode);
730
 
                if (err < 0)
731
 
                        goto error;
732
 
                /* in case the slave doesn't support S16 format */
733
 
                err = snd_pcm_linear_open(&rec->slave, NULL, SND_PCM_FORMAT_S16,
734
 
                                          rec->slave, 1);
735
 
                if (err < 0)
736
 
                        goto error;
737
 
        } else {
738
 
                err = snd_pcm_open(&rec->slave, pcm_string, stream, mode);
739
 
                if (err < 0)
740
 
                        goto error;
741
 
        }
742
 
 
743
 
        rec->io.version = SND_PCM_IOPLUG_VERSION;
744
 
        rec->io.name = "A52 Output Plugin";
745
 
        rec->io.mmap_rw = 0;
746
 
        rec->io.callback = &a52_ops;
747
 
        rec->io.private_data = rec;
748
 
 
749
 
        err = snd_pcm_ioplug_create(&rec->io, name, stream, mode);
750
 
        if (err < 0)
751
 
                goto error;
752
 
 
753
 
        if ((err = a52_set_hw_constraint(rec)) < 0) {
754
 
                snd_pcm_ioplug_delete(&rec->io);
755
 
                return err;
756
 
        }
757
 
 
758
 
        *pcmp = rec->io.pcm;
759
 
        return 0;
760
 
 
761
 
 error:
762
 
        if (rec->slave)
763
 
                snd_pcm_close(rec->slave);
764
 
        free(rec);
765
 
        return err;
766
 
}
767
 
 
768
 
SND_PCM_PLUGIN_SYMBOL(a52);