root/rat/trunk/audio.c @ 1939

Revision 1939, 15.1 KB (checked in by ucaccsp, 16 years ago)

Rearrange time.c and rat_time.h to be timers.[ch], 'coz it's neater.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * FILE:     audio.c
3 * PROGRAM:  RAT
4 * AUTHOR:   Isidor Kouvelas / Colin Perkins / Orion Hodson
5 *
6 * Created parmaters.c by removing all silence detcetion etc.
7 *
8 * $Revision$
9 * $Date$
10 *
11 * Copyright (c) 1995,1996 University College London
12 * All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, is permitted, for non-commercial use only, provided
16 * that the following conditions are met:
17 * 1. Redistributions of source code must retain the above copyright
18 *    notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 *    notice, this list of conditions and the following disclaimer in the
21 *    documentation and/or other materials provided with the distribution.
22 * 3. All advertising materials mentioning features or use of this software
23 *    must display the following acknowledgement:
24 *      This product includes software developed by the Computer Science
25 *      Department at University College London
26 * 4. Neither the name of the University nor of the Department may be used
27 *    to endorse or promote products derived from this software without
28 *    specific prior written permission.
29 * Use of this software for commercial purposes is explicitly forbidden
30 * unless prior written permission is obtained from the authors.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
43 */
44
45#include "config_unix.h"
46#include "config_win32.h"
47#include "assert.h"
48#include "rat_types.h"
49#include "audio.h"
50#include "util.h"
51#include "session.h"
52#include "transcoder.h"
53#include "ui.h"
54#include "transmit.h"
55#include "mix.h"
56#include "codec.h"
57#include "channel.h"
58#include "cushion.h"
59#include "timers.h"
60#include "receive.h"
61
62/* Zero buf used for writing zero chunks during cushion adaption */
63static sample* audio_zero_buf;
64
65#define C0 +0.46363718
66#define C1 -0.92724705
67#define C2 +0.46363718
68#define D1 -1.9059465
69#define D2 +0.9114024
70
71#define IC0 +475
72#define IC1 -950
73#define IC2 +475
74#define ID1 -1952
75#define ID2 +933
76
77typedef struct s_bias_ctl {
78        /* for 8k pre-filtering */
79        sample y1, y2;
80        sample x1, x2;
81        /* for rest */
82        sample lta;
83        u_char step;
84        int    freq;
85} bias_ctl;
86
87static bias_ctl *
88bias_ctl_create(int channels, int freq)
89{
90        bias_ctl *bc = (bias_ctl*)xmalloc(channels*sizeof(bias_ctl));
91        memset(bc, 0, channels*sizeof(bias_ctl));
92        bc->step = channels;
93        bc->freq = freq;
94        return bc;
95}
96
97__inline static void
98prefilter(bias_ctl *pf, sample *buf, register int len, int step)
99{
100        register int y0, y1, y2;
101        register int x0, x1, x2;
102
103        y1 = pf->y1;
104        y2 = pf->y2;
105        x1 = pf->x1;
106        x2 = pf->x2;
107       
108        while(len-- != 0) {
109                x0 = *buf;
110                y0 = (IC0 * x0 + IC1 * x1 + IC2 * x2 - ID1 * y1 - ID2 * y2) >> 10;
111                *buf = y0 << 1;
112                buf += step;               
113                y2 = y1; y1 = y0;
114                x2 = x1; x1 = x0;
115        }
116
117        pf->y1 = y1;
118        pf->y2 = y2;
119        pf->x1 = x1;
120        pf->x2 = x2;
121}
122
123static void
124remove_lta(bias_ctl *bc, sample *buf, register int len, int step)
125{
126        int  m;
127        m = 0;
128        while (len-- > 0) {
129                m += *buf;
130                *buf -= bc->lta;
131                buf += step;
132        }
133        bc->lta -= (bc->lta - m / len) >> 3;
134}
135
136static void
137bias_ctl_destroy(bias_ctl *bc)
138{
139        xfree(bc);
140}
141
142void
143audio_unbias(bias_ctl *bc, sample *buf, int len)
144{
145        if (bc->freq == 8000) {
146                if (bc->step == 1) {
147                        prefilter(bc, buf, len, 1);
148                } else {
149                        len /= bc->step;
150                        prefilter(bc  , buf  , len, 2);
151                        prefilter(bc+1, buf+1, len, 2);
152                }
153        } else {
154                if (bc->step == 1) {
155                        remove_lta(bc, buf, len, 1);
156                } else {
157                        remove_lta(bc  , buf  , len, 2);
158                        remove_lta(bc+1, buf+1, len, 2);
159                }
160        }
161}
162
163void
164audio_zero(sample *buf, int len, deve_e type)
165{
166        assert(len>=0);
167        switch(type) {
168        case DEV_PCMU:
169                memset(buf, PCMU_AUDIO_ZERO, len);
170                break;
171        case DEV_L8:
172                memset(buf, 0, len);
173                break;
174        case DEV_L16:
175                memset(buf, 0, 2*len);
176                break;
177        default:
178                fprintf(stderr, "%s:%d Type not recognized", __FILE__, __LINE__);
179                break;
180        }
181}
182
183int
184audio_device_read(session_struct *sp, sample *buf, int samples)
185{
186        assert(sp->have_device);
187        if (sp->mode == TRANSCODER) {
188                return transcoder_read(sp->audio_fd, buf, samples);
189        } else {
190                return audio_read(sp->audio_fd, buf, samples);
191        }
192}
193
194int
195audio_device_write(session_struct *sp, sample *buf, int dur)
196{
197        codec_t *cp = get_codec_by_pt(sp->encodings[0]);
198
199        if (sp->have_device)
200                if (sp->mode == TRANSCODER) {
201                        return transcoder_write(sp->audio_fd, buf, dur*cp->channels);
202                } else {
203                        return audio_write(sp->audio_fd, buf, dur * audio_get_channels());
204                }
205        else
206                return (dur * cp->channels);
207}
208
209int
210audio_device_take(session_struct *sp)
211{
212        codec_t         *cp;
213        audio_format    format;
214
215        if (sp->have_device) {
216                return (TRUE);
217        }
218
219        cp = get_codec_by_pt(sp->encodings[0]);
220        format.encoding        = DEV_L16;
221        format.sample_rate     = cp->freq;
222        format.bits_per_sample = 16;
223        format.num_channels    = cp->channels;
224        format.blocksize       = cp->unit_len * cp->channels;
225
226        if (sp->mode == TRANSCODER) {
227                if ((sp->audio_fd = transcoder_open()) == -1) {
228                        return FALSE;
229                }
230                sp->have_device = TRUE;
231        } else {
232                /* XXX should pass a pointer to format ???!!! */
233                if ((sp->audio_fd = audio_open(format)) == -1) {
234                        return FALSE;
235                }
236
237                if (audio_duplex(sp->audio_fd) == FALSE) {
238                        printf("RAT v3.2.0 and later require a full duplex audio device, but \n");
239                        printf("your audio device only supports half-duplex operation. Sorry.\n");
240                        return FALSE;
241                }
242
243                audio_drain(sp->audio_fd);
244                sp->have_device = TRUE;
245       
246                if (sp->input_mode!=AUDIO_NO_DEVICE) {
247                        audio_set_iport(sp->audio_fd, sp->input_mode);
248                        audio_set_gain(sp->audio_fd, sp->input_gain);
249                } else {
250                        sp->input_mode=audio_get_iport(sp->audio_fd);
251                        sp->input_gain=audio_get_gain(sp->audio_fd);
252                }
253                if (sp->output_mode!=AUDIO_NO_DEVICE) {
254                        audio_set_oport(sp->audio_fd, sp->output_mode);
255                        audio_set_volume(sp->audio_fd, sp->output_gain);
256                } else {
257                        sp->output_mode=audio_get_oport(sp->audio_fd);
258                        sp->output_gain=audio_get_volume(sp->audio_fd);
259                }
260        }
261       
262        if (audio_zero_buf == NULL) {
263                audio_zero_buf = (sample*) xmalloc (format.blocksize * sizeof(sample));
264                audio_zero(audio_zero_buf, format.blocksize, DEV_L16);
265        }
266
267        if ((sp->audio_fd != -1) && (sp->mode != TRANSCODER)) {
268                audio_non_block(sp->audio_fd);
269        }
270
271        /* We initialize the pieces above the audio device here since their parameters
272         * depend on what is set here
273         */
274        if (sp->device_clock) xfree(sp->device_clock);
275        sp->device_clock = new_time(sp->clock, cp->freq);
276        sp->meter_period = cp->freq / 15;
277        sp->bc           = bias_ctl_create(cp->channels, cp->freq);
278        sp->tb           = tx_create(sp, (u_int16)cp->unit_len, (u_int16)cp->channels);
279        sp->ms           = mix_create(sp, 32640);
280        cushion_create(&sp->cushion, cp->unit_len);
281        tx_igain_update(sp);
282        ui_update(sp);
283        return sp->have_device;
284}
285
286void
287audio_device_give(session_struct *sp)
288{
289        gettimeofday(&sp->device_time, NULL);
290
291        if (sp->have_device) {
292                tx_stop(sp);
293                if (sp->mode == TRANSCODER) {
294                        transcoder_close(sp->audio_fd);
295                } else {
296                        sp->input_mode = audio_get_iport(sp->audio_fd);
297                        sp->output_mode = audio_get_oport(sp->audio_fd);
298                        audio_close(sp->audio_fd);
299                }
300                sp->audio_fd = -1;
301                sp->have_device = FALSE;
302        } else {
303                return;
304        }
305
306        if (audio_zero_buf) {
307                xfree(audio_zero_buf);
308                audio_zero_buf = NULL;
309        }
310       
311        bias_ctl_destroy(sp->bc);
312        sp->bc = NULL;
313
314        cushion_destroy(sp->cushion);
315        mix_destroy(sp->ms);
316        tx_destroy(sp);
317        playout_buffers_destroy(sp, &sp->playout_buf_list);
318}
319
320void
321audio_device_reconfigure(session_struct *sp)
322{
323        u_int16 oldpt    = sp->encodings[0];
324        audio_device_give(sp);
325        tx_stop(sp);
326        sp->encodings[0] = sp->next_encoding;
327        if (audio_device_take(sp) == FALSE) {
328                /* we failed, fallback */
329                sp->encodings[0] = oldpt;
330                audio_device_take(sp);
331        }
332        channel_set_coder(sp, sp->encodings[0]);
333        sp->next_encoding = -1;
334        ui_update(sp);
335}
336
337
338/* This function needs to be modified to return some indication of how well
339 * or not we are doing.                                                   
340 */
341int
342read_write_audio(session_struct *spi, session_struct *spo,  struct s_mix_info *ms)
343{
344        u_int32 cushion_size, read_dur;
345        struct s_cushion_struct *c;
346        int     trailing_silence, new_cushion, cushion_step, diff, channels;
347        sample  *bufp;
348
349        c = spi->cushion;
350        /*
351         * The loop_delay stuff is meant to help in determining the pause
352         * length in the select in net.c for platforms where we cannot
353         * block on read availability of the audio device.
354         */
355        if ((read_dur = tx_read_audio(spi)) <= 0) {
356                if (spi->last_zero == FALSE) {
357                        spi->loop_estimate += 500;
358                }
359                spi->last_zero  = TRUE;
360                spi->loop_delay = 1000;
361                return 0;
362        } else {
363                if (read_dur > 160 && spi->loop_estimate > 5000) {
364                        spi->loop_estimate -= 250;
365                }
366                spi->last_zero  = FALSE;
367                spi->loop_delay = spi->loop_estimate;
368                assert(spi->loop_delay >= 0);
369                if (spi->have_device == FALSE) {
370                        /* no device means no cushion */
371                        return read_dur;
372                }
373        }
374
375        /* read_dur now reflects the amount of real time it took us to get
376         * through the last cycle of processing.
377         */
378
379        if (spo->lecture == TRUE && spo->auto_lecture == 0) {
380                cushion_update(c, read_dur, CUSHION_MODE_LECTURE);
381        } else {
382                cushion_update(c, read_dur, CUSHION_MODE_CONFERENCE);
383        }
384
385        /* Following code will try to achieve new cushion size without
386         * messing up the audio...
387         * First case is when we are in trouble and the output has gone dry.
388         * In this case we write out a complete new cushion with the desired
389         * size. We do not care how much of it is going to be real audio and
390         * how much silence so long as the silence is at the head of the new
391         * cushion. If the silence was at the end we would be creating
392         * another silence gap...
393         */
394        cushion_size = cushion_get_size(c);
395        channels = audio_get_channels();
396
397        if ( cushion_size < read_dur ) {
398                /* Use a step for the cushion to keep things nicely rounded   */
399                /* in the mixing. Round it up.                                */
400                new_cushion = cushion_use_estimate(c);
401                /* The mix routine also needs to know for how long the output */
402                /* went dry so that it can adjust the time.                   */
403                mix_get_new_cushion(ms,
404                                    cushion_size,
405                                    new_cushion,
406                                    (read_dur - cushion_size),
407                                    &bufp);
408                audio_device_write(spo, bufp, new_cushion);
409                if (spo->out_file) {
410                        fwrite(bufp, BYTES_PER_SAMPLE, new_cushion, spo->out_file);
411                }
412                debug_msg("catch up! read_dur(%d) > cushion_size(%d)\n",
413                        read_dur,
414                        cushion_size);
415                cushion_size = new_cushion;
416        } else {
417                trailing_silence = mix_get_audio(ms, read_dur * channels, &bufp);
418                cushion_step = cushion_get_step(c);
419                diff  = 0;
420
421                if (trailing_silence > cushion_step) {
422                        /* Check whether we need to adjust the cushion */
423                        diff = cushion_diff_estimate_size(c);
424                        if (abs(diff) < cushion_step) {
425                                diff = 0;
426                        }
427                }
428               
429                /* If diff is less than zero then we must decrease the */
430                /* cushion so loose some of the trailing silence.      */
431                if (diff < 0 && mix_active(ms) == FALSE && spi->playout_buf_list == NULL) {
432                        /* Only decrease cushion if not playing anything out */
433                        read_dur -= cushion_step;
434                        cushion_step_down(c);
435                        debug_msg("Decreasing cushion\n");
436                }
437                audio_device_write(spo, bufp, read_dur);
438                if (spo->out_file) {
439                        fwrite(bufp, BYTES_PER_SAMPLE, read_dur, spo->out_file);
440                }
441                /*
442                 * If diff is greater than zero then we must increase the
443                 * cushion so increase the amount of trailing silence.
444                 */
445                if (diff > 0) {
446                        audio_device_write(spo, audio_zero_buf, cushion_step);
447                        if (spo->out_file) {
448                                fwrite(audio_zero_buf, BYTES_PER_SAMPLE, cushion_step, spo->out_file);
449                        }
450                        cushion_step_up(c);
451                        debug_msg("Increasing cushion.\n");
452                }
453        }
454        return (read_dur);
455}
456
457void
458audio_wait_for(session_struct *sp)
459{
460#ifdef WIN32
461        DWORD   dwPeriod;
462        codec_t *cp;
463       
464        cp = get_codec_by_pt(sp->encodings[0]);
465        dwPeriod = cp->unit_len / 2  * 1000 / get_freq(sp->device_clock);
466        /* The blocks we are passing to the audio interface are of duration dwPeriod.
467         * dwPeriod is usually around 20ms (8kHz), but mmtask often doesn't give
468         * us audio that often, more like every 40ms.
469         */
470        while (!audio_is_ready()) {
471                Sleep(dwPeriod);
472        }
473        return;
474#else
475        fd_set rfds;
476        codec_t *cp;
477        struct timeval tv;
478
479        cp         = get_codec_by_pt(sp->encodings[0]);
480        tv.tv_sec  = 0;
481        tv.tv_usec = cp->unit_len / 2 * 1000 / get_freq(sp->device_clock);
482
483        FD_ZERO(&rfds);
484        FD_SET(sp->audio_fd,&rfds);
485        select(sp->audio_fd+1, &rfds, NULL, NULL, &tv);
486        return;
487#endif
488}
Note: See TracBrowser for help on using the browser.