Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
savoirfairelinux
jami-daemon
Commits
c9f06f22
Commit
c9f06f22
authored
Jun 22, 2010
by
Alexandre Savard
Browse files
[#2530] Implement asterisk's jitter buffer
parent
9433f78b
Changes
4
Expand all
Hide whitespace changes
Inline
Side-by-side
sflphone-common/src/audio/Makefile.am
View file @
c9f06f22
...
...
@@ -21,6 +21,7 @@ libaudio_la_SOURCES = \
speexechocancel.cpp
\
audioprocessing.cpp
\
dcblocker.cpp
\
jitterbuf.cpp
\
$(SPEEX_SOURCES_CPP)
noinst_HEADERS
=
\
...
...
@@ -37,6 +38,7 @@ noinst_HEADERS = \
speexechocancel.h
\
audioprocessing.h
\
dcblocker.h
\
jitterbuf.h
\
samplerateconverter.h
libaudio_la_LIBADD
=
\
...
...
sflphone-common/src/audio/audiortp/AudioRtpSession.h
View file @
c9f06f22
...
...
@@ -52,6 +52,8 @@
#include <speex/speex_jitter.h>
#include "audio/jitterbuf.h"
// Frequency (in packet number)
#define RTP_TIMESTAMP_RESET_FREQ 100
...
...
@@ -232,11 +234,22 @@ namespace sfl {
*/
EventQueue
_eventQueue
;
JitterBuffer
*
_jbuffer
;
/**
* Adaptive jitter buffer
*/
jitterbuf
*
_jbuffer
;
/**
* Packet size in ms
*/
int
_packetLength
;
int
_ts
;
int
jitterSeqNum
;
/**
* Current time in ms
*/
int
_currentTime
;
protected:
...
...
@@ -283,13 +296,15 @@ namespace sfl {
_layerFrameSize
=
_audiolayer
->
getFrameSize
();
// in ms
_layerSampleRate
=
_audiolayer
->
getSampleRate
();
_jbuffer
=
jitter_buffer_init
(
20
);
_ts
=
0
;
jitterSeqNum
=
0
;
_jbuffer
=
jb_new
();
// int i = 160;
// jitter_buffer_ctl(_jbuffer, JITTER_BUFFER_SET_MARGIN, &i);
// jitter_buffer_ctl(_jbuffer, JITTER_BUFFER_SET_CONCEALMENT_SIZE, &i);
_jbuffer
->
info
.
conf
.
max_jitterbuf
=
1000
;
_jbuffer
->
info
.
conf
.
target_extra
=
100
;
_jbuffer
->
info
.
silence_begin_ts
=
0
;
_ts
=
0
;
_packetLength
=
20
;
_currentTime
=
0
;
}
template
<
typename
D
>
...
...
@@ -318,7 +333,7 @@ namespace sfl {
delete
_audiocodec
;
_audiocodec
=
NULL
;
}
j
itter_buffer
_destroy
(
_jbuffer
);
j
b
_destroy
(
_jbuffer
);
}
template
<
typename
D
>
...
...
@@ -653,68 +668,51 @@ namespace sfl {
}
const
ost
::
AppDataUnit
*
adu
=
NULL
;
int
packetTimestamp
=
static_cast
<
D
*>
(
this
)
->
getFirstTimestamp
();
adu
=
static_cast
<
D
*>
(
this
)
->
getData
(
packetTimestamp
);
// packetTimestamp = adu->getgetTimestamp();
if
(
adu
==
NULL
)
{
// _debug("No RTP audio stream\n");
return
;
}
unsigned
char
*
spkrData
=
(
unsigned
char
*
)
adu
->
getData
();
// data in char
unsigned
int
size
=
adu
->
getSize
();
// size in char
if
(
!
adu
)
return
;
JitterBufferPacket
jPacketIn
;
jPacketIn
.
data
=
(
char
*
)
spkrData
;
jPacketIn
.
len
=
size
;
// jPacketIn.timestamp = static_cast<D*>(this)->getFirstTimestamp();
jPacketIn
.
timestamp
=
jitterSeqNum
*
_timestampIncrement
;
jPacketIn
.
span
=
_timestampIncrement
;
jPacketIn
.
sequence
=
++
jitterSeqNum
;
unsigned
char
*
spkrDataIn
=
NULL
;
unsigned
int
size
=
0
;
int
result
;
j
itter_buffer_put
(
_jbuffer
,
&
jPacketIn
)
;
j
b_frame
frame
;
JitterBufferPacket
jPacketOut
;
jPacketOut
.
data
=
new
char
[
size
];
jPacketOut
.
len
=
size
;
jPacketIn
.
timestamp
=
0
;
jPacketIn
.
span
=
0
;
jPacketIn
.
sequence
=
0
;
int
desiredSpan
=
_timestampIncrement
;
spx_int32_t
offs
=
0
;
if
(
adu
)
{
spkrDataIn
=
(
unsigned
char
*
)
adu
->
getData
();
// data in char
size
=
adu
->
getSize
();
// size in char
result
=
jb_put
(
_jbuffer
,
spkrDataIn
,
JB_TYPE_VOICE
,
_packetLength
,
_ts
+=
20
,
_currentTime
);
// result = jb_get(_jbuffer, &frame, _currentTime+=20, _packetLength);
}
else
{
_debug
(
"No RTP packet available !!!!!!!!!!!!!!!!!!!!!!!
\n
"
);
}
int
result
=
JITTER_BUFFER_INTERNAL_ERROR
;
result
=
jitter_buffer_get
(
_jbuffer
,
&
jPacketOut
,
desiredSpan
,
&
offs
);
jitter_buffer_tick
(
_jbuffer
);
result
=
jb_get
(
_jbuffer
,
&
frame
,
_currentTime
+=
20
,
_packetLength
);
/*
switch(result) {
case JITTER_BUFFER_OK:
_debug("JITTER_BUFFER_OK");
break;
case JITTER_BUFFER_MISSING:
_debug("JITTER_BUFFER_MISSING");
break;
case JITTER_BUFFER_INTERNAL_ERROR:
_debug("JITTER_BUFFER_INTERNAL_ERROR");
break;
case JITTER_BUFFER_BAD_ARGUMENT:
_debug("JITTER_BUFFER_BAD_ARGUMENT");
break;
default:
_debug("Unknown error");
break;
case 0: printf("You\'ve got frame!\n"); break;
case 1: printf("Here\'s an audio frame you should just drop. Ask me again for this time..\n"); break;
case 2: printf("There\'s no frame scheduled for this time.\n"); break;
case 3: printf("Please interpolate an interpl-length frame for this time (either we need to grow, or there was a lost frame)\n"); break;
case 4: printf("Empty\n"); break;
default: printf("Unknown returned value\n"); break;
}
*/
// DTMF over RTP, size must be over 4 in order to process it as voice data
if
(
size
>
4
)
{
// processDataDecode(spkrData, size);
if
(
result
==
JITTER_BUFFER_OK
)
processDataDecode
((
unsigned
char
*
)
jPacketOut
.
data
,
jPacketOut
.
len
);
// processDataDecode(spkrDataIn, size);
if
(
result
==
0
)
{
processDataDecode
((
unsigned
char
*
)(
frame
.
data
),
160
);
}
else
{
_debug
(
"bad data"
);
}
}
else
{
// _debug("RTP: Received an RTP event with payload: %d", adu->getType());
...
...
@@ -722,8 +720,7 @@ namespace sfl {
// _debug("RTP: Data received %d", dtmf->event);
}
delete
jPacketOut
.
data
;
delete
adu
;
// delete adu;
}
template
<
typename
D
>
...
...
@@ -742,8 +739,6 @@ namespace sfl {
// Timestamp must be initialized randomly
_timestamp
=
static_cast
<
D
*>
(
this
)
->
getCurrentTimestamp
();
_ts
=
0
;
int
sessionWaiting
;
int
threadSleep
=
0
;
...
...
sflphone-common/src/audio/jitterbuf.cpp
0 → 100755
View file @
c9f06f22
This diff is collapsed.
Click to expand it.
sflphone-common/src/audio/jitterbuf.h
0 → 100755
View file @
c9f06f22
/*
* jitterbuf: an application-independent jitterbuffer
*
* Copyrights:
* Copyright (C) 2004-2005, Horizon Wimba, Inc.
*
* Contributors:
* Steve Kann <stevek@stevek.com>
*
* This program is free software, distributed under the terms of
* the GNU Lesser (Library) General Public License
*
* Copyright on this file is disclaimed to Digium for inclusion in Asterisk
*/
/*! \file
* \brief
* jitterbuf: an application-independent jitterbuffer
* \ref jitterbuf.c
*/
#ifndef _JITTERBUF_H_
#define _JITTERBUF_H_
#ifdef __cplusplus
extern
"C"
{
#endif
/*! \name configuration constants */
/*@{ */
/*! Number of historical timestamps to use in calculating jitter and drift */
#define JB_HISTORY_SZ 500
/*! what percentage of timestamps should we drop from the history when we examine it;
* this might eventually be something made configurable */
#define JB_HISTORY_DROPPCT 3
/*! the maximum droppct we can handle (say it was configurable). */
#define JB_HISTORY_DROPPCT_MAX 4
/*! the size of the buffer we use to keep the top and botton timestamps for dropping */
#define JB_HISTORY_MAXBUF_SZ JB_HISTORY_SZ * JB_HISTORY_DROPPCT_MAX / 100
/*! amount of additional jitterbuffer adjustment */
#define JB_TARGET_EXTRA 40
/*! ms between growing and shrinking; may not be honored if jitterbuffer runs out of space */
#define JB_ADJUST_DELAY 40
/*@} */
enum
jb_return_code
{
/* return codes */
JB_OK
,
/* 0 */
JB_EMPTY
,
/* 1 */
JB_NOFRAME
,
/* 2 */
JB_INTERP
,
/* 3 */
JB_DROP
,
/* 4 */
JB_SCHED
/* 5 */
};
enum
jb_frame_type
{
/* frame types */
JB_TYPE_CONTROL
,
/*!< 0 */
JB_TYPE_VOICE
,
/*!< 1 */
JB_TYPE_VIDEO
,
/*!< 2 - reserved */
JB_TYPE_SILENCE
/*!< 3 */
};
typedef
struct
jb_conf
{
/* settings */
long
max_jitterbuf
;
/*!< defines a hard clamp to use in setting the jitter buffer delay */
long
resync_threshold
;
/*!< the jb will resync when delay increases to (2 * jitter) + this param */
long
max_contig_interp
;
/*!< the max interp frames to return in a row */
long
target_extra
;
/*!< amount of additional jitterbuffer adjustment, overrides JB_TARGET_EXTRA */
}
jb_conf
;
typedef
struct
jb_info
{
jb_conf
conf
;
/* statistics */
long
frames_in
;
/*!< number of frames input to the jitterbuffer.*/
long
frames_out
;
/*!< number of frames output from the jitterbuffer.*/
long
frames_late
;
/*!< number of frames which were too late, and dropped.*/
long
frames_lost
;
/*!< number of missing frames.*/
long
frames_dropped
;
/*!< number of frames dropped (shrinkage) */
long
frames_ooo
;
/*!< number of frames received out-of-order */
long
frames_cur
;
/*!< number of frames presently in jb, awaiting delivery.*/
long
jitter
;
/*!< jitter measured within current history interval*/
long
min
;
/*!< minimum lateness within current history interval */
long
current
;
/*!< the present jitterbuffer adjustment */
long
target
;
/*!< the target jitterbuffer adjustment */
long
losspct
;
/*!< recent lost frame percentage (* 1000) */
long
next_voice_ts
;
/*!< the ts of the next frame to be read from the jb - in receiver's time */
long
last_voice_ms
;
/*!< the duration of the last voice frame */
long
silence_begin_ts
;
/*!< the time of the last CNG frame, when in silence */
long
last_adjustment
;
/*!< the time of the last adjustment */
long
last_delay
;
/*!< the last now added to history */
long
cnt_delay_discont
;
/*!< the count of discontinuous delays */
long
resync_offset
;
/*!< the amount to offset ts to support resyncs */
long
cnt_contig_interp
;
/*!< the number of contiguous interp frames returned */
}
jb_info
;
typedef
struct
jb_frame
{
void
*
data
;
/* the frame data */
long
ts
;
/* the relative delivery time expected */
long
ms
;
/* the time covered by this frame, in sec/8000 */
enum
jb_frame_type
type
;
/* the type of frame */
struct
jb_frame
*
next
,
*
prev
;
}
jb_frame
;
typedef
struct
jitterbuf
{
jb_info
info
;
/* history */
long
history
[
JB_HISTORY_SZ
];
/*!< history */
int
hist_ptr
;
/*!< points to index in history for next entry */
long
hist_maxbuf
[
JB_HISTORY_MAXBUF_SZ
];
/*!< a sorted buffer of the max delays (highest first) */
long
hist_minbuf
[
JB_HISTORY_MAXBUF_SZ
];
/*!< a sorted buffer of the min delays (lowest first) */
int
hist_maxbuf_valid
;
/*!< are the "maxbuf"/minbuf valid? */
unsigned
int
dropem
:
1
;
/*!< flag to indicate dropping frames (overload) */
jb_frame
*
frames
;
/*!< queued frames */
jb_frame
*
free
;
/*!< free frames (avoid malloc?) */
}
jitterbuf
;
/*! \brief new jitterbuf */
jitterbuf
*
jb_new
(
void
);
/*! \brief destroy jitterbuf */
void
jb_destroy
(
jitterbuf
*
jb
);
/*! \brief reset jitterbuf
* \note The jitterbuffer should be empty before you call this, otherwise
* you will leak queued frames, and some internal structures */
void
jb_reset
(
jitterbuf
*
jb
);
/*!\brief queue a frame
*
* data=frame data, timings (in ms): ms=length of frame (for voice), ts=ts (sender's time)
* now=now (in receiver's time) return value is one of
* JB_OK: Frame added. Last call to jb_next() still valid
* JB_DROP: Drop this frame immediately
* JB_SCHED: Frame added. Call jb_next() to get a new time for the next frame
*/
enum
jb_return_code
jb_put
(
jitterbuf
*
jb
,
void
*
data
,
const
enum
jb_frame_type
type
,
long
ms
,
long
ts
,
long
now
);
/*! \brief get a frame for time now (receiver's time) return value is one of
* JB_OK: You've got frame!
* JB_DROP: Here's an audio frame you should just drop. Ask me again for this time..
* JB_NOFRAME: There's no frame scheduled for this time.
* JB_INTERP: Please interpolate an interpl-length frame for this time (either we need to grow, or there was a lost frame)
* JB_EMPTY: The jb is empty.
*/
enum
jb_return_code
jb_get
(
jitterbuf
*
jb
,
jb_frame
*
frame
,
long
now
,
long
interpl
);
/*! \brief unconditionally get frames from jitterbuf until empty */
enum
jb_return_code
jb_getall
(
jitterbuf
*
jb
,
jb_frame
*
frameout
);
/*! \brief when is the next frame due out, in receiver's time (0=EMPTY)
* This value may change as frames are added (esp non-audio frames) */
long
jb_next
(
jitterbuf
*
jb
);
/*! \brief get jitterbuf info: only "statistics" may be valid */
enum
jb_return_code
jb_getinfo
(
jitterbuf
*
jb
,
jb_info
*
stats
);
/* some diagnostics */
void
jb_dbginfo
(
jitterbuf
*
jb
);
/*! \brief set jitterbuf conf */
enum
jb_return_code
jb_setconf
(
jitterbuf
*
jb
,
jb_conf
*
conf
);
typedef
void
__attribute__
((
format
(
printf
,
1
,
2
)))
(
*
jb_output_function_t
)(
const
char
*
fmt
,
...);
void
jb_setoutput
(
jb_output_function_t
err
,
jb_output_function_t
warn
,
jb_output_function_t
dbg
);
#ifdef __cplusplus
}
#endif
#endif
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment