summaryrefslogtreecommitdiffstats
path: root/tinyDAV/include/tinydav/audio/tdav_jitterbuffer.h
blob: c6d2449727f940d5064c0654066401eb28f49513 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
/* File from: http://cms.speakup.nl/tech/opensource/jitterbuffer/verslag-20051209.pdf/ */

/*******************************************************
 * jitterbuffer: 
 * an application-independent jitterbuffer, which tries 
 * to achieve the maximum user perception during a call.
 * For more information look at:
 * http://www.speakup.nl/opensource/jitterbuffer/
 *
 * Copyright on this file is held by:
 * - Jesse Kaijen <jesse@speakup.nl>  
 * - SpeakUp <info@speakup.nl>
 *
 * Contributors:
 * Jesse Kaijen <jesse@speakup.nl>
 *
 * Version: 1.1
 * 
 * Changelog:
* 1.0 => 1.1 (2006-03-24) (thanks to Micheal Jerris, freeswitch.org)
 * - added MSVC 2005 project files
 * - added JB_NOJB as return value
 *
 *
 * This program is free software, distributed under the terms of:
 * - the GNU Lesser (Library) General Public License
 * - the Mozilla Public License
 * 
 * if you are interested in an different licence type, please contact us.
 *
 * How to use the jitterbuffer, please look at the comments 
 * in the headerfile.
 *
 * Further details on specific implementations, 
 * please look at the comments in the code file.
 */

#ifndef TINYDAV_JITTERBUFFER_H_
#define TINYDAV_JITTERBUFFER_H_

#include "tinydav_config.h"

#if !(HAVE_SPEEX_DSP && HAVE_SPEEX_JB)

TDAV_BEGIN_DECLS

/***********
 * The header file consists of four parts.
 * - configuration constants, structs and parameter definitions
 * - functions
 * - How to use the jitterbuffer and 
 *   which responsibilities do YOU have
 * - debug messages explained
 */


// configuration constants
/* Number of historical timestamps to use in calculating jitter and jitterbuffer size */ 
#ifndef JB_HISTORY_SIZE
#	define JB_HISTORY_SIZE 500
#endif

/* minimum jitterbuffer size, disabled if 0 */
#define JB_MIN_SIZE 0
/* maximum jitterbuffer size, disabled if 0 */ 
#define JB_MAX_SIZE 0
 /* maximum successive interpolating frames, disabled if 0 */
#define JB_MAX_SUCCESSIVE_INTERP 0
/* amount of extra delay allowed before shrinking */
#define JB_ALLOW_EXTRA_DELAY 30																														
/* ms between growing */
#define JB_WAIT_GROW 60
/* ms between shrinking */
#define JB_WAIT_SHRINK 250
/* ms that the JB max may be off */
#define JB_MAX_DIFF 6000 //in a RTP stream the max_diff may be 3000 packets (most packets are 20ms)

//structs
typedef struct jb_info {
	long frames_received;       /* Number of frames received by the jitterbuffer */
  long frames_late;           /* Number of frames that were late */
  long frames_lost;           /* Number of frames that were lost */
  long frames_ooo;            /* Number of frames that were Out Of Order */
  long frames_dropped;        /* Number of frames that were dropped due shrinkage of the jitterbuffer */
  long frames_dropped_twice;  /* Number of frames that were dropped because this timestamp was already in the jitterbuffer */
                              
  long delay;     /* Current delay due the jitterbuffer */
	long jitter; 		/* jitter measured within current history interval*/
	long losspct; 	/* recent lost frame percentage (network and jitterbuffer loss) */
	                            
	long delay_target;   /* The delay where we want to grow to */
	long losspct_jb;     /* recent lost percentage due the jitterbuffer */
	long last_voice_ms;	 /* the duration of the last voice frame */
  short silence;       /* If we are in silence 1-yes 0-no */
  long iqr;            /* Inter Quartile Range of current history, if the squareroot is taken it is a good estimate of jitter */
} jb_info;

typedef struct jb_frame {
	void *data;		                /* the frame data */
	long ts;	                    /* the senders timestamp */
	long ms;	                    /* length of this frame in ms */
	int  type;	                  /* the type of frame */
	int codec;                    /* codec of this frame, undefined if nonvoice */
	struct jb_frame *next, *prev; /* pointers to the next and previous frames in the queue */ 
} jb_frame;

typedef struct jb_hist_element {
	long delay; /* difference between time of arrival and senders timestamp */
	long ts;    /* senders timestamp */
	long ms;    /* length of this frame in ms */
	int codec;  /* wich codec this frame has */
} jb_hist_element;								

typedef struct jb_settings {
  /* settings */
	long min_jb;	              /* defines a hard clamp to use in setting the jitterbuffer delay */
  long max_jb;	              /* defines a hard clamp to use in setting the jitterbuffer delay */
  long max_successive_interp; /* the maximum count of successive interpolations before assuming silence */
  long extra_delay;           /* amount of extra delay allowed before shrinking */
  long wait_grow;             /* ms between growing */
  long wait_shrink;           /* ms between shrinking */
  long max_diff;              /* maximum number of milliseconds the jitterbuffer may be off */
} jb_settings;

typedef struct jitterbuffer {
	struct jb_hist_element hist[JB_HISTORY_SIZE]; /* the history of the last received frames */
	long hist_sorted_delay[JB_HISTORY_SIZE];      /* a sorted buffer of the delays (lowest first) */
	long hist_sorted_timestamp[JB_HISTORY_SIZE];  /* a sorted buffer of the timestamps (lowest first) */
	
	int  hist_pointer;          /* points to index in history for next entry */
	long last_adjustment;       /* the time of the last adjustment (growing or shrinking) */
  long next_voice_time;	      /* the next ts is to be read from the jb (senders timestamp) */
	long cnt_successive_interp; /* the count of consecutive interpolation frames */	
	long silence_begin_ts;      /* the time of the last CNG frame, when in silence */
	long min;		                /* the clock difference within current history interval */
	long current; 		          /* the present jitterbuffer adjustment */
	long target; 		            /* the target jitterbuffer adjustment */
	long last_delay;            /* the delay of the last packet, used for calc. jitter */
	                            
	jb_frame *voiceframes; 	 /* queued voiceframes */
	jb_frame *controlframes; /* queued controlframes */
	jb_settings settings;    /* the settings of the jitterbuffer */
	jb_info info;            /* the statistics of the jitterbuffer */
} jitterbuffer;

//parameter definitions
/* return codes */
#define JB_OK		0
#define JB_EMPTY	1
#define JB_NOFRAME	2
#define JB_INTERP	3
#define JB_NOJB		4


/* frame types */
#define JB_TYPE_CONTROL	1
#define JB_TYPE_VOICE	2
#define JB_TYPE_SILENCE	3

/* the jitterbuffer behaives different for each codec. */
/* Look in the code if a codec has his function defined */
/* default is g711x behaiviour */
#define JB_CODEC_SPEEX 10       //NOT defined
#define JB_CODEC_ILBC 9         //NOT defined
#define JB_CODEC_GSM_EFR 8
#define JB_CODEC_GSM_FR 7       //NOT defined
#define JB_CODEC_G723_1 6
#define JB_CODEC_G729A 5
#define JB_CODEC_G729 4
#define JB_CODEC_G711x_PLC 3
#define JB_CODEC_G711x 2
#define JB_CODEC_OTHER 1        //NOT defined


/*
 * Creates a new jitterbuffer and sets the default settings.
 * Always use this function for creating a new jitterbuffer. 
 */
jitterbuffer *jb_new();

/*
 * The control frames and possible personal settings are kept. 
 * History and voice/silence frames are destroyed. 
 */
void jb_reset(jitterbuffer *jb);

/*
 * Resets the jitterbuffer totally, all the control/voice/silence frames are destroyed
 * default settings are put as well. 
 */
void jb_reset_all(jitterbuffer *jb);

/*
 * Destroy the jitterbuffer and any frame within. 
 * Always use this function for destroying a jitterbuffer,
 * otherwise there is a chance of memory leaking.
 */
void jb_destroy(jitterbuffer *jb);

/*
 * Define your own settings for the jitterbuffer. Only settings !=0
 * are put in the jitterbuffer.
 */
void jb_set_settings(jitterbuffer *jb, jb_settings *settings);

/*
 * Get the statistics for the jitterbuffer. 
 * Copying the statistics directly for the jitterbuffer won't work because
 * The statistics are only calculated when calling this function.
 */
void jb_get_info(jitterbuffer *jb, jb_info *stats);

/*
 * Get the current settings of the jitterbuffer.
 */
void jb_get_settings(jitterbuffer *jb, jb_settings *settings);

/*
 * Gives an estimation of the MOS of a call given the
 * packetloss p, delay d, and wich codec is used.
 * The assumption is made that the echo cancelation is around 37dB.
 */
float jb_guess_mos(float p, long d, int codec);

/*
 * returns JB_OK if there are still frames left in the jitterbuffer
 * otherwise JB_EMPTY is returned.
 */
int jb_has_frames(jitterbuffer *jb);

/*
 * put a packet(frame) into the jitterbuffer.
 * *data - points to the packet
 * type - type of packet, JB_CONTROL|JB_VOICE|JB_SILENCE
 * ms - duration of frame (only voice)
 * ts - timestamp sender
 * now - current timestamp (timestamp of arrival)
 * codec - which codec the frame holds (only voice), if not defined, g711x will be used
 *
 * if type==control @REQUIRE: *data, type, ts, now
 * if type==voice   @REQUIRE: *data, type, ms, ts, now @OPTIONAL: codec
 * if type==silence @REQUIRE: *data, type, ts, now
 * on return *data is undefined
 */
void jb_put(jitterbuffer *jb, void *data, int type, long ms, long ts, long now, int codec);

/*
 * Get a packet from the jitterbuffer if it's available.
 * control packets have a higher priority above voice and silence packets
 * they are always delivered as fast as possible. The delay of the jitterbuffer
 * doesn't work for these packets. 
 * @REQUIRE 1<interpl <= jb->settings->extra_delay (=default JB_ALLOW_EXTRA_DELAY)
 *
 * return will be:
 * JB_OK, *data points to the packet
 * JB_INTERP, please interpolate for interpl milliseconds
 * JB_NOFRAME, no frame scheduled
 * JB_EMPTY, the jitterbuffer is empty
 */
int jb_get(jitterbuffer *jb, void **data, long now, long interpl);

/* debug functions */
typedef 		void (*jb_output_function_t)(const char *fmt, ...);
void 			jb_setoutput(jb_output_function_t warn, jb_output_function_t err, jb_output_function_t dbg);


/*******************************
 * The use of the jitterbuffer *
 *******************************
 * Always create a new jitterbuffer with jb_new().
 * Always destroy a jitterbuffer with jb_destroy().
 *
 * There is no lock(mutex) mechanism, that your responsibility.
 * The reason for this is that different environments require
 * different ways of implementing a lock.
 *
 * The following functions require a lock on the jitterbuffer:
 * jb_reset(), jb_reset_all(), jb_destroy(), jb_set_settings(),
 * jb_get_info(), jb_get_settings(), jb_has_frames(), jb_put(),
 * jb_get()
 *
 * The following functions do NOT require a lock on the jitterbuffer:
 * jb_new(), jb_guess_mos()
 *
 * Since control packets have a higher priority above any other packet
 * a call may already be ended while there is audio left to play. We
 * advice that you poll the jitterbuffer if there are frames left.
 *
 * If the audiopath is oneway (eg. voicemailbox) and the latency doesn't
 * matter, we advice to set a minimum jitterbuffer size. Then there is
 * less loss and the quality is better.
 */


/****************************
 * debug messages explained *
 ****************************
 * N  - jb_new()
 * R  - jb_reset()
 * r  - jb_reset_all()
 * D  - jb_destroy()
 * S  - jb_set_settings()
 * H  - jb_has_frames()
 * I  - jb_get_info()
 * S  - jb_get_settings()
 * pC - jb_put() put Control packet
 * pT - jb_put() Timestamp was already in the queue
 * pV - jb_put() put Voice packet
 * pS - jb_put() put Silence packet
 *
 * A  - jb_get()
 * // below are all the possible debug info when trying to get a packet
 * gC - get_control() - there is a control message
 * gs - get_voice() - there is a silence frame
 * gS - get_voice() - we are in silence
 * gL - get_voice() - are in silence, frame is late
 * gP - get_voice() - are in silence, play frame (end of silence)
 * ag - get_voicecase() - grow little bit (diff < interpl/2)
 * aG - get_voicecase() - grow interpl
 * as - get_voicecase() - shrink by voiceframe we throw out
 * aS - get_voicecase() - shrink by interpl
 * aN - get_voicecase() - no time yet
 * aL - get_voicecase() - frame is late
 * aP - get_voicecase() - play frame
 * aI - get_voicecase() - interpolate
 */

TDAV_END_DECLS

#endif /* !(HAVE_SPEEX_DSP && HAVE_SPEEX_JB) */

#endif /* TINYDAV_JITTERBUFFER_H_ */

OpenPOWER on IntegriCloud