comparison spandsp-0.0.6pre17/src/playout.c @ 4:26cd8f1ef0b1

import spandsp-0.0.6pre17
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 15:50:58 +0200
parents
children
comparison
equal deleted inserted replaced
3:c6c5a16ce2f2 4:26cd8f1ef0b1
1 /*
2 * SpanDSP - a series of DSP components for telephony
3 *
4 * playout.c
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2005 Steve Underwood
9 *
10 * All rights reserved.
11 *
12 * This was kicked off from jitter buffering code
13 * Copyright (C) 2004, Horizon Wimba, Inc.
14 * Author Steve Kann <stevek@stevek.com>
15 * However, there isn't a lot of the original left, now. The original
16 * was licenced under the LGPL, so any remaining fragments are
17 * compatible with the GPL licence used here.
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU Lesser General Public License version 2.1,
21 * as published by the Free Software Foundation.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU Lesser General Public License for more details.
27 *
28 * You should have received a copy of the GNU Lesser General Public
29 * License along with this program; if not, write to the Free Software
30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 *
32 * $Id: playout.c,v 1.17 2009/02/10 13:06:46 steveu Exp $
33 */
34
35 #if defined(HAVE_CONFIG_H)
36 #include "config.h"
37 #endif
38
39 #include <stdio.h>
40 #include <inttypes.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <limits.h>
44
45 #include "spandsp/telephony.h"
46 #include "spandsp/playout.h"
47
48 static playout_frame_t *queue_get(playout_state_t *s, timestamp_t sender_stamp)
49 {
50 playout_frame_t *frame;
51
52 if ((frame = s->first_frame) == NULL)
53 return NULL;
54
55 if (sender_stamp >= frame->sender_stamp)
56 {
57 /* Remove this frame from the queue */
58 if (frame->later)
59 {
60 frame->later->earlier = NULL;
61 s->first_frame = frame->later;
62 }
63 else
64 {
65 /* The queue is now empty */
66 s->first_frame = NULL;
67 s->last_frame = NULL;
68 }
69 return frame;
70 }
71
72 return NULL;
73 }
74 /*- End of function --------------------------------------------------------*/
75
76 SPAN_DECLARE(timestamp_t) playout_next_due(playout_state_t *s)
77 {
78 return s->last_speech_sender_stamp + s->last_speech_sender_len;
79 }
80 /*- End of function --------------------------------------------------------*/
81
82 SPAN_DECLARE(timestamp_t) playout_current_length(playout_state_t *s)
83 {
84 return s->target_buffer_length;
85 }
86 /*- End of function --------------------------------------------------------*/
87
88 SPAN_DECLARE(playout_frame_t *) playout_get_unconditional(playout_state_t *s)
89 {
90 playout_frame_t *frame;
91
92 if ((frame = queue_get(s, 0x7FFFFFFF)))
93 {
94 /* Put it on the free list */
95 frame->later = s->free_frames;
96 s->free_frames = frame;
97
98 /* We return the frame pointer, even though it's on the free list.
99 The caller *must* copy the data before this frame has any chance
100 of being reused. */
101 }
102 return frame;
103 }
104 /*- End of function --------------------------------------------------------*/
105
106 SPAN_DECLARE(int) playout_get(playout_state_t *s, playout_frame_t *frameout, timestamp_t now)
107 {
108 playout_frame_t *frame;
109
110 /* Make the last_speech_sender_stamp the current expected one. */
111 s->last_speech_sender_stamp += s->last_speech_sender_len;
112 if ((frame = queue_get(s, s->last_speech_sender_stamp)) == NULL)
113 {
114 /* The required frame was not received (or at least not in time) */
115 s->frames_missing++;
116 return PLAYOUT_FILLIN;
117 }
118
119 if (s->dynamic && frame->type == PLAYOUT_TYPE_SPEECH)
120 {
121 /* Assess whether the buffer length is appropriate */
122 if (!s->not_first)
123 {
124 /* Prime things the first time through */
125 s->not_first = TRUE;
126 s->latest_expected = frame->receiver_stamp + s->min_length;
127 }
128 /* Leaky integrate the rate of occurance of frames received just in time and late */
129 s->state_late += ((((frame->receiver_stamp > s->latest_expected) ? 0x10000000 : 0) - s->state_late) >> 8);
130 s->state_just_in_time += ((((frame->receiver_stamp > s->latest_expected - frame->sender_len) ? 0x10000000 : 0) - s->state_just_in_time) >> 8);
131 s->latest_expected += frame->sender_len;
132
133 if (s->state_late > s->dropable_threshold)
134 {
135 if (s->since_last_step < 10)
136 {
137 if (s->target_buffer_length < s->max_length - 2)
138 {
139 /* The late bin is too big - increase buffering */
140 s->target_buffer_length += 3*frame->sender_len;
141 s->latest_expected += 3*frame->sender_len;
142 s->state_just_in_time = s->dropable_threshold;
143 s->state_late = 0;
144 s->since_last_step = 0;
145
146 s->last_speech_sender_stamp -= 3*s->last_speech_sender_len;
147 }
148 }
149 else
150 {
151 if (s->target_buffer_length < s->max_length)
152 {
153 /* The late bin is too big - increase buffering */
154 s->target_buffer_length += frame->sender_len;
155 s->latest_expected += frame->sender_len;
156 s->state_just_in_time = s->dropable_threshold;
157 s->state_late = 0;
158 s->since_last_step = 0;
159
160 s->last_speech_sender_stamp -= s->last_speech_sender_len;
161 }
162 }
163 }
164 else if (s->since_last_step > 500 && s->state_just_in_time < s->dropable_threshold)
165 {
166 if (s->target_buffer_length > s->min_length)
167 {
168 /* The just-in-time bin is pretty small - decrease buffering */
169 s->target_buffer_length -= frame->sender_len;
170 s->latest_expected -= frame->sender_len;
171 s->state_just_in_time = s->dropable_threshold;
172 s->state_late = 0;
173 s->since_last_step = 0;
174
175 s->last_speech_sender_stamp += s->last_speech_sender_len;
176 }
177 }
178 s->since_last_step++;
179 }
180
181 /* If its not a speech frame, just return it. */
182 if (frame->type != PLAYOUT_TYPE_SPEECH)
183 {
184 /* Rewind last_speech_sender_stamp, since this isn't speech */
185 s->last_speech_sender_stamp -= s->last_speech_sender_len;
186
187 *frameout = *frame;
188 /* Put it on the free list */
189 frame->later = s->free_frames;
190 s->free_frames = frame;
191
192 s->frames_out++;
193 return PLAYOUT_OK;
194 }
195 if (frame->sender_stamp < s->last_speech_sender_stamp)
196 {
197 /* This speech frame is late */
198 *frameout = *frame;
199 /* Put it on the free list */
200 frame->later = s->free_frames;
201 s->free_frames = frame;
202
203 /* Rewind last_speech_sender_stamp, since we're just dumping */
204 s->last_speech_sender_stamp -= s->last_speech_sender_len;
205 s->frames_out++;
206 s->frames_late++;
207 s->frames_missing--;
208 return PLAYOUT_DROP;
209 }
210 /* Keep track of frame sizes, to allow for variable sized frames */
211 if (frame->sender_len > 0)
212 s->last_speech_sender_len = frame->sender_len;
213
214 /* Normal case. Return the frame, and increment stuff */
215 *frameout = *frame;
216 /* Put it on the free list */
217 frame->later = s->free_frames;
218 s->free_frames = frame;
219
220 s->frames_out++;
221 return PLAYOUT_OK;
222 }
223 /*- End of function --------------------------------------------------------*/
224
225 SPAN_DECLARE(int) playout_put(playout_state_t *s, void *data, int type, timestamp_t sender_len, timestamp_t sender_stamp, timestamp_t receiver_stamp)
226 {
227 playout_frame_t *frame;
228 playout_frame_t *p;
229
230 /* When a frame arrives we just queue it in order. We leave all the tricky stuff until frames
231 are read from the queue. */
232 s->frames_in++;
233
234 /* Acquire a frame */
235 if ((frame = s->free_frames))
236 {
237 s->free_frames = frame->later;
238 }
239 else
240 {
241 if ((frame = (playout_frame_t *) malloc(sizeof(*frame))) == NULL)
242 return PLAYOUT_ERROR;
243 }
244
245 /* Fill out the frame */
246 frame->data = data;
247 frame->type = type;
248 frame->sender_stamp = sender_stamp;
249 frame->sender_len = sender_len;
250 frame->receiver_stamp = receiver_stamp;
251
252 /* Frames are kept in a list, sorted by the timestamp assigned by the sender. */
253 if (s->last_frame == NULL)
254 {
255 /* The queue is empty. */
256 frame->later = NULL;
257 frame->earlier = NULL;
258 s->first_frame = frame;
259 s->last_frame = frame;
260 }
261 else if (sender_stamp >= s->last_frame->sender_stamp)
262 {
263 /* Frame goes at the end of the queue. */
264 frame->later = NULL;
265 frame->earlier = s->last_frame;
266 s->last_frame->later = frame;
267 s->last_frame = frame;
268 }
269 else
270 {
271 /* Frame is out of sequence. */
272 s->frames_oos++;
273
274 /* Find where it should go in the queue */
275 p = s->last_frame;
276 while (sender_stamp < p->sender_stamp && p->earlier)
277 p = p->earlier;
278
279 if (p->earlier)
280 {
281 /* It needs to go somewhere in the queue */
282 frame->later = p->later;
283 frame->earlier = p;
284 p->later->earlier = frame;
285 p->later = frame;
286 }
287 else
288 {
289 /* It needs to go at the very beginning of the queue */
290 frame->later = p;
291 frame->earlier = NULL;
292 p->earlier = frame;
293 s->first_frame = frame;
294 }
295 }
296
297 if (s->start && type == PLAYOUT_TYPE_SPEECH)
298 {
299 s->last_speech_sender_stamp = sender_stamp - sender_len - s->min_length;
300 s->last_speech_sender_len = sender_len;
301 s->start = FALSE;
302 }
303
304 return PLAYOUT_OK;
305 }
306 /*- End of function --------------------------------------------------------*/
307
308 SPAN_DECLARE(void) playout_restart(playout_state_t *s, int min_length, int max_length)
309 {
310 playout_frame_t *frame;
311 playout_frame_t *next;
312
313 /* Free all the frames on the free list */
314 for (frame = s->free_frames; frame; frame = next)
315 {
316 next = frame->later;
317 free(frame);
318 }
319
320 memset(s, 0, sizeof(*s));
321 s->dynamic = (min_length < max_length);
322 s->min_length = min_length;
323 s->max_length = (max_length > min_length) ? max_length : min_length;
324 s->dropable_threshold = 1*0x10000000/100;
325 s->start = TRUE;
326 s->since_last_step = 0x7FFFFFFF;
327 /* Start with the minimum buffer length allowed, and work from there */
328 s->actual_buffer_length =
329 s->target_buffer_length = (s->max_length - s->min_length)/2;
330 }
331 /*- End of function --------------------------------------------------------*/
332
333 SPAN_DECLARE(playout_state_t *) playout_init(int min_length, int max_length)
334 {
335 playout_state_t *s;
336
337 if ((s = (playout_state_t *) malloc(sizeof(playout_state_t))) == NULL)
338 return NULL;
339 memset(s, 0, sizeof(*s));
340 playout_restart(s, min_length, max_length);
341 return s;
342 }
343 /*- End of function --------------------------------------------------------*/
344
345 SPAN_DECLARE(int) playout_release(playout_state_t *s)
346 {
347 playout_frame_t *frame;
348 playout_frame_t *next;
349
350 /* Free all the frames in the queue. In most cases these should have been
351 removed already, so their associated data could be freed. */
352 for (frame = s->first_frame; frame; frame = next)
353 {
354 next = frame->later;
355 free(frame);
356 }
357 /* Free all the frames on the free list */
358 for (frame = s->free_frames; frame; frame = next)
359 {
360 next = frame->later;
361 free(frame);
362 }
363 return 0;
364 }
365 /*- End of function --------------------------------------------------------*/
366
367 SPAN_DECLARE(int) playout_free(playout_state_t *s)
368 {
369 if (s)
370 {
371 playout_release(s);
372 /* Finally, free ourselves! */
373 free(s);
374 }
375 return 0;
376 }
377 /*- End of function --------------------------------------------------------*/
378 /*- End of file ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.