root/rat/trunk/mix.c @ 2241

Revision 2241, 15.0 KB (checked in by ucacoxh, 15 years ago)

- Added source flush if mix fails (source sample rate change).

- Added repair failure code, should only fail if sample rate changes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * FILE:        mix.c
3 * PROGRAM:     RAT
4 * AUTHOR:      Isidor Kouvelas
5 * MODIFIED BY: Orion Hodson + Colin Perkins
6 *
7 * $Revision$
8 * $Date$
9 *
10 * Copyright (c) 1995-98 University College London
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, is permitted, for non-commercial use only, provided
15 * that the following conditions are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 *    must display the following acknowledgement:
23 *      This product includes software developed by the Computer Science
24 *      Department at University College London
25 * 4. Neither the name of the University nor of the Department may be used
26 *    to endorse or promote products derived from this software without
27 *    specific prior written permission.
28 * Use of this software for commercial purposes is explicitly forbidden
29 * unless prior written permission is obtained from the authors.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
32 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
35 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 * SUCH DAMAGE.
42 */
43
44#include "config_unix.h"
45#include "config_win32.h"
46#include "memory.h"
47#include "util.h"
48#include "mix.h"
49#include "session.h"
50#include "codec_types.h"
51#include "codec.h"
52#include "audio_util.h"
53#include "audio_fmt.h"
54#include "timers.h"
55#include "rtcp_pckt.h"
56#include "rtcp_db.h"
57#include "source.h"
58#include "playout.h"
59#include "debug.h"
60#include "parameters.h"
61#include "ui.h"
62
63typedef struct s_mix_info {
64        int     buf_len;        /* Length of circular buffer */
65        int     head, tail;     /* Index to head and tail of buffer */
66        ts_t    head_time;      /* Time of latest sample in buffer.
67                                 * In fact pad_time has to be taken into
68                                 * account to get the actual value. */
69        ts_t    tail_time;      /* Current time */
70        int     dist;           /* Distance between head and tail.
71                                 * We must make sure that this is kept
72                                 * equal to value of the device cushion
73                                 * unless there is no audio to mix. */
74        sample  *mix_buffer;    /* The buffer containing mixed audio data. */
75        int      channels;      /* number of channels being mixed. */
76        int      rate;          /* Sampling frequency */
77} mix_struct;
78
79typedef void (*mix_f)(sample *buf, sample *incoming, int len);
80static mix_f audio_mix_fn;
81
82#define ROUND_UP(x, y)  (x) % (y) > 0 ? (x) - (x) % (y) : (x)
83
84/*
85 * Initialise the circular buffer that is used in mixing.
86 * The buffer length should be as big as the largest possible
87 * device cushion used (and maybe some more).
88 * We allocate space three times the requested one so that we
89 * dont have to copy everything when we hit the boundaries..
90 */
91int
92mix_create(mix_struct **ppms, int sample_rate, int sample_channels, int buffer_length)
93{
94        mix_struct *pms;
95
96        pms = (mix_struct *) xmalloc(sizeof(mix_struct));
97        if (pms) {
98                memset(pms, 0 , sizeof(mix_struct));
99                pms->channels    = sample_channels;
100                pms->rate        = sample_rate;
101                pms->buf_len     = buffer_length * pms->channels;
102                pms->mix_buffer  = (sample *)xmalloc(3 * pms->buf_len * BYTES_PER_SAMPLE);
103                audio_zero(pms->mix_buffer, 3 * buffer_length , DEV_S16);
104                pms->mix_buffer += pms->buf_len;
105                pms->head_time = pms->tail_time = ts_map32(pms->rate, 0);
106                *ppms = pms;
107
108
109                audio_mix_fn = audio_mix;
110#ifdef WIN32
111                if (mmx_present()) {
112                        audio_mix_fn = audio_mix_mmx;
113                }
114#endif /* WIN32 */
115                return TRUE;
116        }
117        return FALSE;
118}
119
120void
121mix_destroy(mix_struct **ppms)
122{
123        mix_struct *pms;
124       
125        assert(ppms);
126        pms = *ppms;
127        assert(pms);
128
129        xfree(pms->mix_buffer - pms->buf_len); /* yuk! ouch! splat! */
130        xfree(pms);
131        *ppms = NULL;
132}
133
134static void
135mix_zero(mix_struct *ms, int offset, int len)
136{
137        assert(len < ms->buf_len);
138        if (offset + len > ms->buf_len) {
139                audio_zero(ms->mix_buffer + offset, ms->buf_len - offset, DEV_S16);
140                audio_zero(ms->mix_buffer, offset + len-ms->buf_len, DEV_S16);
141        } else {
142                audio_zero(ms->mix_buffer + offset, len, DEV_S16);
143        }
144        xmemchk();
145}
146
147
148/* mix_process mixes a single audio frame into mix buffer.  It returns
149 * TRUE if incoming audio frame is compatible with mix, FALSE
150 * otherwise.  */
151
152int
153mix_process(mix_struct          *ms,
154            rtcp_dbentry        *dbe,
155            coded_unit          *frame,
156            ts_t                 playout)
157{
158        sample  *samples;
159        u_int32  nticks, nsamples, pos;
160        u_int16  channels, rate;
161        ts_t     frame_period, expected_playout, delta, new_head_time;
162
163        assert((ms->head + ms->buf_len - ms->tail) % ms->buf_len == ms->dist);
164
165        codec_get_native_info(frame->id, &rate, &channels);
166
167        if (rate != ms->rate || channels != ms->channels) {
168                /* This should only occur if source changes sample rate
169                 * mid-stream and before buffering runs dry in end host.
170                 * This should be a very rare event.
171                 */
172                debug_msg("Unit (%d, %d) not compitible with mix (%d, %d).\n",
173                          rate,
174                          channels,
175                          ms->rate,
176                          ms->channels);
177                return FALSE;
178        }
179
180        assert(rate     == (u_int32)ms->rate);
181        assert(channels == (u_int32)ms->channels);
182
183        nticks          = frame->data_len / (sizeof(sample) * channels);
184        frame_period    = ts_map32(rate, nticks);
185
186        if (dbe->first_mix) {
187                debug_msg("New mix\n");
188                dbe->last_mixed = ts_sub(playout, frame_period);
189                dbe->first_mix  = 0;
190        }
191
192        assert(ts_gt(playout, dbe->last_mixed));
193
194        samples  = (sample*)frame->data;
195        nsamples = frame->data_len / sizeof(sample);
196               
197        /* Check for overlap in decoded frames */
198        expected_playout = ts_add(dbe->last_mixed, frame_period);
199
200        if (!ts_eq(expected_playout, playout)) {
201                if (ts_gt(expected_playout, playout)) {
202                        delta = ts_sub(expected_playout, playout);
203                        debug_msg("Overlapping units\n");
204                        if (ts_gt(frame_period, delta)) {
205                                u_int32  trim = delta.ticks * ms->channels;
206                                samples  += trim;
207                                nsamples -= trim;
208                                debug_msg("Trimmed %d samples\n", trim);
209                        } else {
210                                debug_msg("Skipped unit\n");
211                        }
212                } else {
213                        if (expected_playout.ticks - playout.ticks != 0) {
214                                debug_msg("Gap between units %d %d\n", expected_playout.ticks, playout.ticks);
215                        }
216                }
217        }
218
219        /* Zero ahead if necessary */
220
221        new_head_time = ts_add(playout, ts_map32(ms->rate, nsamples / ms->channels));
222        if (ts_eq(ms->head_time, ms->tail_time)) {
223                ms->head_time = ms->tail_time = playout;
224        }
225
226        if (ts_gt(new_head_time, ms->head_time))  {
227                int zeros;
228                delta = ts_sub(new_head_time, ms->head_time);
229                zeros = delta.ticks * ms->channels;
230                mix_zero(ms, ms->head, zeros);
231                ms->dist += zeros;
232                ms->head += zeros;
233                ms->head %= ms->buf_len;
234                ms->head_time = ts_add(ms->head_time, delta);
235        }
236        assert((ms->head + ms->buf_len - ms->tail) % ms->buf_len == ms->dist);                                         
237        assert(!ts_gt(playout, ms->head_time));
238
239        /* Work out where to write the data */
240        delta = ts_sub(ms->head_time, playout);
241        pos   = (ms->head - delta.ticks*ms->channels) % ms->buf_len;
242        if (pos > 0x7fffffff) {
243                pos += ms->buf_len;
244                assert(pos < (u_int32)ms->buf_len);
245        }
246       
247        if (pos + nsamples > (u_int32)ms->buf_len) {
248                audio_mix_fn(ms->mix_buffer + pos,
249                             samples,
250                             ms->buf_len - pos);
251                xmemchk();
252                audio_mix_fn(ms->mix_buffer,
253                             samples + (ms->buf_len - pos) * ms->channels,
254                             pos + nsamples - ms->buf_len);
255                xmemchk();
256        } else {
257                audio_mix_fn(ms->mix_buffer + pos,
258                             samples,
259                             nsamples);
260                xmemchk();
261        }
262        dbe->last_mixed = playout;
263
264        return TRUE;
265}
266
267/*
268 * The mix_get_audio function returns a pointer to "amount" samples of mixed
269 * audio data, suitable for playout (ie: you can do audio_device_write() with
270 * the returned data).
271 *
272 * This function was modified so that it returns the amount of
273 * silence at the end of the buffer returned so that the cushion
274 * adjustment functions can use it to decrease the cushion.
275 *
276 * Note: amount is number of samples to get and not sampling intervals!
277 */
278
279int
280mix_get_audio(mix_struct *ms, int amount, sample **bufp)
281{
282        int     silence;
283
284        xmemchk();
285        assert(amount < ms->buf_len);
286        if (amount > ms->dist) {
287                /*
288                 * If we dont have enough to give one of two things
289                 * must have happened.
290                 * a) There was silence :-)
291                 * b) There wasn't enough time to decode the stuff...
292                 * In either case we will have to return silence for
293                 * now so zero the rest of the buffer and move the head.
294                 */
295                silence = amount - ms->dist;
296                if (ms->head + silence > ms->buf_len) {
297#ifdef DEBUG_MIX
298                        fprintf(stderr,"Insufficient audio: zeroing end of mix buffer %d %d\n", ms->buf_len - ms->head, silence + ms->head - ms->buf_len);
299#endif
300                        audio_zero(ms->mix_buffer + ms->head, ms->buf_len - ms->head, DEV_S16);
301                        audio_zero(ms->mix_buffer, silence + ms->head - ms->buf_len, DEV_S16);
302                } else {
303                        audio_zero(ms->mix_buffer + ms->head, silence, DEV_S16);
304                }
305                xmemchk();
306                ms->head      += silence;
307                ms->head      %= ms->buf_len;
308                ms->head_time  = ts_add(ms->head_time,
309                                        ts_map32(ms->rate, silence/ms->channels));
310                ms->dist       = amount;
311                assert((ms->head + ms->buf_len - ms->tail) % ms->buf_len == ms->dist);
312        } else {
313                silence = 0;
314        }
315
316        if (ms->tail + amount > ms->buf_len) {
317                /*
318                 * We have run into the end of the buffer so we will
319                 * have to copy stuff before we return it.
320                 * The space after the 'end' of the buffer is used
321                 * for this purpose as the space before is used to
322                 * hold silence that is returned in case the cushion
323                 * grows too much.
324                 * Of course we could use both here (depending on which
325                 * direction involves less copying) and copy actual
326                 * voice data in the case a cushion grows into it.
327                 * The problem is that in that case we are probably in
328                 * trouble and want to avoid doing too much...
329                 *
330                 * Also if the device is working in similar boundaries
331                 * to our chunk sizes and we are a bit careful about the
332                 * possible cushion sizes this case can be avoided.
333                 */
334                xmemchk();
335                memcpy(ms->mix_buffer + ms->buf_len, ms->mix_buffer, BYTES_PER_SAMPLE*(ms->tail + amount - ms->buf_len));
336                xmemchk();
337#ifdef DEBUG_MIX
338                fprintf(stderr,"Copying start of mix len: %d\n", ms->tail + amount - ms->buf_len);
339#endif
340        }
341        *bufp = ms->mix_buffer + ms->tail;
342        ms->tail_time = ts_add(ms->tail_time,
343                               ts_map32(ms->rate, amount/ms->channels));
344        ms->tail      += amount;
345        ms->tail      %= ms->buf_len;
346        ms->dist      -= amount;
347        assert((ms->head + ms->buf_len - ms->tail) % ms->buf_len == ms->dist);
348
349        return silence;
350}
351
352/*
353 * We need the amount of time we went dry so that we can make a time
354 * adjustment to keep in sync with the receive buffer etc...
355 *
356 */
357void
358mix_get_new_cushion(mix_struct *ms, int last_cushion_size, int new_cushion_size,
359                        int dry_time, sample **bufp)
360{
361        int     diff, elapsed_time;
362
363#ifdef DEBUG_MIX
364        fprintf(stderr, "Getting new cushion %d old %d\n", new_cushion_size, last_cushion_size);
365#endif
366
367        elapsed_time = (last_cushion_size + dry_time);
368        diff = abs(new_cushion_size - elapsed_time) * ms->channels;
369#ifdef DEBUG_MIX
370        fprintf(stderr,"new cushion size %d\n",new_cushion_size);
371#endif
372        if (new_cushion_size > elapsed_time) {
373                /*
374                 * New cushion is larger so move tail back to get
375                 * the right amount and end up at the correct time.
376                 * The effect of moving the tail is that some old
377                 * audio and/or silence will be replayed. We do not
378                 * care to much as we are right after an underflow.
379                 */
380                ms->tail -= diff;
381                if (ms->tail < 0) {
382                        ms->tail += ms->buf_len;
383                }
384                ms->dist += diff;
385                assert(ms->dist <= ms->buf_len);
386                ms->tail_time = ts_sub(ms->tail_time,
387                                       ts_map32(ms->rate, diff/ms->channels));
388                assert((ms->head + ms->buf_len - ms->tail) % ms->buf_len == ms->dist);
389        } else if (new_cushion_size < elapsed_time) {
390                /*
391                 * New cushion is smaller so we have to throw away
392                 * some audio.
393                 */
394                ms->tail += diff;
395                ms->tail %= ms->buf_len;
396                ms->tail_time = ts_add(ms->tail_time,
397                                       ts_map32(ms->rate, diff/ms->channels));
398                if (diff > ms->dist) {
399                        ms->head = ms->tail;
400                        ms->head_time = ms->tail_time;
401                        ms->dist = 0;
402                } else {
403                        ms->dist -= diff;
404                }
405                assert((ms->head + ms->buf_len - ms->tail) % ms->buf_len == ms->dist);
406        }
407        mix_get_audio(ms, new_cushion_size * ms->channels, bufp);
408}
409
410#define POWER_METER_SAMPLES 160
411
412void
413mix_update_ui(session_struct *sp, mix_struct *ms)
414{
415        sample  *bp;
416
417        if (ms->tail < POWER_METER_SAMPLES) {
418                bp = ms->mix_buffer + ms->buf_len - POWER_METER_SAMPLES * ms->channels;
419        } else {
420                bp = ms->mix_buffer + ms->tail - POWER_METER_SAMPLES;
421        }
422        ui_output_level(sp, lin2vu(avg_audio_energy(bp, POWER_METER_SAMPLES, 1), 100, VU_OUTPUT));
423}
424
425int
426mix_active(mix_struct *ms)
427{
428        return !ts_eq(ms->head_time, ms->tail_time);
429}
430
431__inline int
432mix_compatible(mix_struct *ms, int rate, int channels)
433{
434        assert(rate > 10);
435        assert(channels >=0 && channels < 3);
436        return (ms->rate == rate) && (ms->channels == channels);
437}
Note: See TracBrowser for help on using the browser.