Commit 89a29efe authored by Simon Morlat's avatar Simon Morlat
Browse files

Add test suite for oRTP-1.0.0 new jitter buffer.

parent 2de7d15c
......@@ -828,7 +828,7 @@ if test "$ortp_enabled" = 'true'; then
fi
fi
if test "$external_ortp" = 'true'; then
PKG_CHECK_MODULES(ORTP, ortp >= 0.24.1, ,
PKG_CHECK_MODULES(ORTP, ortp >= 1.0.0, ,
[ AC_MSG_ERROR([Couldn't find ortp library]) ] )
fi
else
......@@ -981,29 +981,32 @@ fi
AM_CONDITIONAL(BUILD_V4L1, test x$found_v4l1 = xyes )
AM_CONDITIONAL(BUILD_V4L2, test x$found_v4l2 = xyes )
AC_PATH_PROG(PCAP,pcap-config,false)
AM_CONDITIONAL(HAVE_PCAP, test $PCAP != false)
AC_ARG_ENABLE(pcap,
[AS_HELP_STRING([--enable-pcap], [Enable pcap library (default=no)])],
[AS_HELP_STRING([--enable-pcap], [Enable pcap library (default=auto)])],
[case "${enableval}" in
yes) enable_pcap=yes ;;
no) enable_pcap=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-pcap) ;;
esac],
[enable_pcap=no]
[enable_pcap=auto]
)
AM_CONDITIONAL(ENABLE_PCAP, test x$enable_pcap = xyes)
if test x$enable_pcap == xyes ; then
if test x$enable_pcap != xno ; then
AC_PATH_PROG(PCAP,pcap-config,false)
if test $PCAP != false ; then
PCAP_LIBS=`pcap-config --libs`
PCAP_CFLAGS=`pcap-config --cflags`
AC_SUBST(PCAP_LIBS)
AC_SUBST(PCAP_CFLAGS)
AC_DEFINE(HAVE_PCAP,1,[whether we compile with libpcap support])
enable_pcap=yes
else
enable_pcap=no
fi
fi
AM_CONDITIONAL(ENABLE_PCAP, test x$enable_pcap = xyes)
dnl ##################################################
......@@ -1307,4 +1310,5 @@ printf "* %-30s %s\n" "Video support" $video
printf "* %-30s %s\n" "sRTP encryption" $have_srtp
printf "* %-30s %s\n" "zRTP encryption" $zrtp
printf "* %-30s %s\n" "Non-free codecs" $non_free_codecs
printf "* %-30s %s\n" "pcap support" $enable_pcap
......@@ -73,6 +73,8 @@ set(HEADER_FILES
zrtp.h
msrtt4103.h
msasync.h
msudp.h
mspcapfileplayer.h
)
set(MEDIASTREAMER2_HEADER_FILES )
......
......@@ -52,7 +52,9 @@ mediastreamer2_include_HEADERS=allfilters.h \
upnp_igd.h \
x11_helper.h \
zrtp.h \
msasync.h
msasync.h \
mspcapfileplayer.h \
msudp.h
EXTRA_DIST=$(mediastreamer2_include_HEADERS)
......@@ -156,7 +156,9 @@ typedef enum MSFilterId{
MS_MEDIACODEC_H264_DEC_ID,
MS_MEDIACODEC_H264_ENC_ID,
MS_BV16_DEC_ID,
MS_BV16_ENC_ID
MS_BV16_ENC_ID,
MS_UDP_SEND_ID,
MS_PCAP_FILE_PLAYER_ID
} MSFilterId;
#endif
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef mspcapfileplayer_h
#define mspcapfileplayer_h
#include <mediastreamer2/msfilter.h>
/**
* This enum provides two differents outputs of the filter depending on your use case.
* If you want to plug this filter directly to a decoder, you may want to skip RTP header
* and directly get payload data using @MSPCAPFilePlayerLayerPayload. If you want to
* send these packet over the network, you may want to keep the RTP header using
* @MSPCAPFilePlayerLayerRTP.
**/
typedef enum _MSPCAPFilePlayerLayer {
MSPCAPFilePlayerLayerRTP, /* skip IP, UDP, but keeps RTP header + underlying layers */
MSPCAPFilePlayerLayerPayload, /* skip IP, UDP, RTP, but keeps RTP content */
} MSPCAPFilePlayerLayer;
/**
* This enum provides two differents way of incrementing time depending on your use case.
* If you want to play packets at the rate they were encoded, you should use @MSPCAPFilePlayerTimeRefRTP
* which contains timestamps value written by the encoder.
* Instead, if you want to replay a receiver-based PCAP stream as it was heard by the receiver,
* you should use @MSPCAPFilePlayerTimeRefCapture.
*/
typedef enum _MSPCAPFilePlayerTimeRef {
MSPCAPFilePlayerTimeRefRTP, /* use timestamps contained in RTP header to replay packets, written by the encoder */
MSPCAPFilePlayerTimeRefCapture, /* use time of packet capture to replay them, specially useful in case of receiver-based capture */
} MSPCAPFilePlayerTimeRef;
/*methods*/
#define MS_PCAP_FILE_PLAYER_SET_LAYER MS_FILTER_METHOD(MS_PCAP_FILE_PLAYER_ID,0,MSPCAPFilePlayerLayer)
#define MS_PCAP_FILE_PLAYER_SET_TIMEREF MS_FILTER_METHOD(MS_PCAP_FILE_PLAYER_ID,1,MSPCAPFilePlayerTimeRef)
#define MS_PCAP_FILE_PLAYER_SET_TO_PORT MS_FILTER_METHOD(MS_PCAP_FILE_PLAYER_ID,2,unsigned)
#endif
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef msudp_hh
#define msudp_hh
#include <mediastreamer2/msfilter.h>
typedef struct _MSIPPort {
char *ip;
int port;
} MSIPPort;
#define MS_UDP_SEND_SET_DESTINATION MS_FILTER_METHOD(MS_UDP_SEND_ID,1,const MSIPPort*)
extern MSFilterDesc ms_udp_send_desc;
#endif
......@@ -45,4 +45,5 @@ src/videofilters/x11video.c
src/videofilters/msdscap.cc
src/voip/ice.c
src/audiofilters/msgenericplc.c
src/otherfilters/mspcapfileplayer.c
......@@ -168,6 +168,8 @@ set(VOIP_SOURCE_FILES_C
utils/kiss_fft.h
utils/kiss_fftr.c
utils/kiss_fftr.h
utils/pcap_sender.c
utils/pcap_sender.h
utils/stream_regulator.c
voip/audioconference.c
voip/audiostream.c
......@@ -184,6 +186,7 @@ set(VOIP_SOURCE_FILES_C
voip/qualityindicator.c
otherfilters/rfc4103_source.c
otherfilters/rfc4103_sink.c
otherfilters/msudp.c
voip/rfc4103_textstream.c
voip/ringstream.c
voip/stun.c
......@@ -428,6 +431,10 @@ if(MATROSKA2_FOUND)
)
endif()
if(PCAP_FOUND)
list(APPEND VOIP_SOURCE_FILES_C src/otherfilters/mspcapfileplayer.c)
endif()
set(VOIP_SOURCE_FILES_ALL ${VOIP_SOURCE_FILES_C} ${VOIP_SOURCE_FILES_CXX} ${VOIP_SOURCE_FILES_OBJC})
add_custom_target(ms2-voipdescs-header
......
......@@ -91,6 +91,10 @@ libmediastreamer_voip_la_SOURCES=
nodist_EXTRA_libmediastreamer_base_la_SOURCES = dummy.cxx
if ENABLE_PCAP
libmediastreamer_voip_la_SOURCES += otherfilters/mspcapfileplayer.c
endif
if ORTP_ENABLED
BUILT_SOURCES+=voipdescs.h
libmediastreamer_voip_la_SOURCES+= voip/private.h \
......@@ -104,6 +108,7 @@ libmediastreamer_voip_la_SOURCES+= voip/private.h \
voip/msmediaplayer.c \
voip/ice.c \
otherfilters/msrtp.c \
otherfilters/msudp.c \
voip/qualityindicator.c \
voip/audioconference.c \
voip/bitratedriver.c \
......@@ -113,7 +118,8 @@ libmediastreamer_voip_la_SOURCES+= voip/private.h \
voip/stun.c \
crypto/ms_srtp.c \
crypto/dtls_srtp.c \
voip/msiframerequestslimiter.c
voip/msiframerequestslimiter.c \
utils/pcap_sender.c utils/pcap_sender.h
else
libmediastreamer_base_la_SOURCES+= ortp-deps/logging.c \
ortp-deps/port.c \
......
......@@ -26,6 +26,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "mediastreamer2/msutils.h"
#include "mediastreamer2/msvaddtx.h"
#include "ortp/utils.h"
#ifdef HAVE_G729B
#include "bcg729/encoder.h"
#endif
......@@ -40,7 +42,7 @@ typedef struct _VadDtxContext{
int silence_mode;/*set to 1 if a silence period is running*/
#ifndef HAVE_G729B
float energy;
ortp_extremum max;
OrtpExtremum max;
#else
bcg729EncoderChannelContextStruct *encoderChannelContext;
MSBufferizer *bufferizer;
......
......@@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "mediastreamer2/msvolume.h"
#include "mediastreamer2/msticker.h"
#include "mediastreamer2/msutils.h"
#include "ortp/utils.h"
#include <math.h>
#ifdef HAVE_SPEEXDSP
......@@ -72,8 +73,8 @@ typedef struct Volume{
float ng_floorgain;
float ng_gain;
MSBufferizer *buffer;
ortp_extremum min;
ortp_extremum max;
OrtpExtremum min;
OrtpExtremum max;
bool_t agc_enabled;
bool_t noise_gate_enabled;
bool_t remove_dc;
......
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#if defined(HAVE_CONFIG_H)
#include "mediastreamer-config.h"
#endif
#include "mediastreamer2/mspcapfileplayer.h"
#include "mediastreamer2/msfileplayer.h"
#include "waveheader.h"
#include "mediastreamer2/msticker.h"
#include <pcap/pcap.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
static int player_close(MSFilter *f, void *arg);
struct _PlayerData{
int fd;
MSPlayerState state;
int rate;
int hsize;
int pause_time;
int count;
int samplesize;
int datalink_size;
unsigned to_port;
uint32_t ts;
bool_t swap;
bool_t is_raw;
pcap_t *pcap;
struct pcap_pkthdr *pcap_hdr;
const u_char *pcap_data;
bool_t pcap_started;
uint64_t pcap_initial_time;
uint32_t pcap_initial_ts;
uint16_t pcap_seq;
struct timeval pcap_initial_timeval;
MSPCAPFilePlayerTimeRef pcap_timeref;
MSPCAPFilePlayerLayer pcap_layer;
};
typedef struct _PlayerData PlayerData;
static void player_init(MSFilter *f){
PlayerData *d=ms_new0(PlayerData,1);
d->fd=-1;
d->state=MSPlayerClosed;
d->swap=FALSE;
d->rate=8000;
d->samplesize=2;
d->datalink_size=0;
d->to_port=0;
d->hsize=0;
d->pause_time=0;
d->count=0;
d->ts=0;
d->is_raw=TRUE;
d->pcap = NULL;
d->pcap_hdr = NULL;
d->pcap_data = NULL;
d->pcap_started = FALSE;
d->pcap_initial_ts = 0;
d->pcap_seq = 0;
d->pcap_timeref = MSPCAPFilePlayerTimeRefRTP;
d->pcap_layer = MSPCAPFilePlayerLayerPayload;
f->data=d;
}
static uint link_layer_size(int datalink) {
switch (datalink) {
//cf http://www.tcpdump.org/linktypes.html
case 1: return 14; //LINKTYPE_ETHERNET: Ethernet
case 113: return 16; //LINKTYPE_LINUX_SLL: Linux "cooked" capture encapsulation
default:
ms_error("Unsupported network type %d, assuming no link header...", datalink);
return 0;
}
}
static int player_open(MSFilter *f, void *arg){
PlayerData *d=(PlayerData*)f->data;
int fd;
const char *file=(const char*)arg;
if (d->fd!=-1){
player_close(f,NULL);
}
if ((fd=open(file,O_RDONLY|O_BINARY))==-1){
ms_warning("MSFilePlayer[%p]: failed to open %s: %s",f,file,strerror(errno));
return -1;
}
d->state=MSPlayerPaused;
d->fd=fd;
d->ts=0;
d->pcap = NULL;
d->pcap_started = FALSE;
if (strstr(file, ".pcap")) {
char err[PCAP_ERRBUF_SIZE];
d->pcap = pcap_open_offline(file, err);
if (d->pcap == NULL) {
ms_error("MSFilePlayer[%p]: failed to open pcap file: %s",f,err);
d->fd=-1;
close(fd);
return -1;
}
d->datalink_size = link_layer_size(pcap_datalink(d->pcap));
ms_filter_notify_no_arg(f,MS_FILTER_OUTPUT_FMT_CHANGED);
ms_message("MSFilePlayer[%p]: %s opened: rate=%i",f,file,d->rate);
return 0;
} else {
ms_error("Unsupported file extension: %s", file);
return -1;
}
}
static int player_start(MSFilter *f, void *arg){
PlayerData *d=(PlayerData*)f->data;
if (d->state==MSPlayerPaused)
d->state=MSPlayerPlaying;
return 0;
}
static int player_pause(MSFilter *f, void *arg){
PlayerData *d=(PlayerData*)f->data;
ms_filter_lock(f);
if (d->state==MSPlayerPlaying){
d->state=MSPlayerPaused;
}
ms_filter_unlock(f);
return 0;
}
static int player_close(MSFilter *f, void *arg){
PlayerData *d=(PlayerData*)f->data;
if (d->pcap) pcap_close(d->pcap);
if (d->fd!=-1) close(d->fd);
d->fd=-1;
d->state=MSPlayerClosed;
return 0;
}
static int player_get_state(MSFilter *f, void *arg){
PlayerData *d=(PlayerData*)f->data;
*(int*)arg=d->state;
return 0;
}
static void player_uninit(MSFilter *f){
PlayerData *d=(PlayerData*)f->data;
if (d->fd!=-1) player_close(f,NULL);
ms_free(d);
}
static void player_process(MSFilter *f){
PlayerData *d=(PlayerData*)f->data;
ms_filter_lock(f);
if (d->state==MSPlayerPlaying) {
if (d->pcap) {
int res;
bool_t cont = TRUE;
do {
if (d->pcap_data && d->pcap_hdr) {
/* The PCAP data has already been read at previous iteration. */
res = 1;
} else {
res = pcap_next_ex(d->pcap, &d->pcap_hdr, &d->pcap_data);
}
if (res == -2) {
ms_filter_notify_no_arg(f,MS_PLAYER_EOF);
ms_filter_notify_no_arg(f, MS_FILE_PLAYER_EOF);
} else if (res == -1) {
ms_error("Error while reading next pcap packet: %s", pcap_geterr(d->pcap));
} else if (res > 0) {
const u_char *link_layer_header = &d->pcap_data[0];
const u_char *ip_header = link_layer_header + d->datalink_size; // sizeof(link_layer_header)
const u_char *udp_header = ip_header + 20; // sizeof(ipv4_header)
const u_char *rtp_header = udp_header + 8; // sizeof(udp_header)
const u_char *payload = rtp_header + 12; // sizeof(rtp_header)
int headers_size = payload - link_layer_header;
unsigned to_port = ntohs(*(uint16_t*)(udp_header + 2));
if (d->to_port != 0 && d->to_port != to_port) {
// Skip packets with invalid from port
ms_debug("Outputting wrong-from-port packet (got %u but expected %u), ignoring", to_port, d->to_port);
d->pcap_hdr = NULL;
d->pcap_data = NULL;
} else if (((int)d->pcap_hdr->caplen >= headers_size) && ((rtp_header[0] >> 6) == 2)) {
// Check headers size and RTP version
mblk_t *om = NULL;
uint16_t pcap_seq = ntohs(*((uint16_t*)(rtp_header + 2)));
uint32_t ts = ntohl(*((uint32_t*)(rtp_header + 4)));
uint32_t diff_ms;
bool_t markbit=rtp_header[1]>>7;
int headers_size = payload - link_layer_header;
int bytes_pcap = d->pcap_hdr->caplen - headers_size;
if (d->pcap_started == FALSE) {
d->pcap_started = TRUE;
d->pcap_initial_ts = ts;
d->pcap_initial_time = f->ticker->time;
d->pcap_seq = pcap_seq;
ms_message("initial ts=%u, seq=%u",ts,pcap_seq);
d->pcap_initial_timeval.tv_sec = d->pcap_hdr->ts.tv_sec;
d->pcap_initial_timeval.tv_usec = d->pcap_hdr->ts.tv_usec;
}
diff_ms = (d->pcap_timeref == MSPCAPFilePlayerTimeRefRTP) ?
((ts - d->pcap_initial_ts) * 1000) / d->rate
: 1000 * (d->pcap_hdr->ts.tv_sec - d->pcap_initial_timeval.tv_sec)
+ (d->pcap_hdr->ts.tv_usec - d->pcap_initial_timeval.tv_usec) / 1000;
if ((f->ticker->time - d->pcap_initial_time) >= diff_ms) {
if (d->pcap_layer == MSPCAPFilePlayerLayerRTP) {
int headers_size = link_layer_header - rtp_header;
int bytes_pcap = d->pcap_hdr->caplen + headers_size;
/*uncommented to add some offset to all packets*/
#if 0
if (pcap_seq>3000){
ts += 1e6;
*((uint32_t*)(rtp_header + 4)) = htonl(ts);
}
#endif
om = allocb(bytes_pcap, 0);
memcpy(om->b_wptr, rtp_header, bytes_pcap);
om->b_wptr += bytes_pcap;
} else {
if (pcap_seq >= d->pcap_seq) {
om = allocb(bytes_pcap, 0);
memcpy(om->b_wptr, payload, bytes_pcap);
om->b_wptr += bytes_pcap;
mblk_set_cseq(om, pcap_seq);
mblk_set_timestamp_info(om, f->ticker->time);
mblk_set_marker_info(om,markbit);
}
}
if (om != NULL) {
ms_debug("Outputting RTP packet of size %i, seq=%u markbit=%i", bytes_pcap, pcap_seq, (int)markbit);
ms_queue_put(f->outputs[0], om);
}
d->pcap_seq = pcap_seq;
d->pcap_hdr = NULL;
d->pcap_data = NULL;
} else {
ms_debug("Outputting non-RTP packet, stopping");
cont = FALSE;
}
} else {
// Ignore wrong RTP packet
ms_debug("Outputting wrong-RTP packet, ignoring");
d->pcap_hdr = NULL;
d->pcap_data = NULL;
}
}
} while ((res > 0) && cont);
}
}
ms_filter_unlock(f);
}
static int player_get_sr(MSFilter *f, void*arg){
PlayerData *d=(PlayerData*)f->data;
*((int*)arg)=d->rate;
return 0;
}
static int player_set_sr(MSFilter *f, void *arg) {
PlayerData *d = (PlayerData *)f->data;
if (d->is_raw) d->rate = *((int *)arg);
else return -1;
ms_message("MSFilePlayer[%p]: new rate=%i",f,d->rate);
return 0;
}
static int player_set_layer(MSFilter *f, void *arg){
PlayerData *d=(PlayerData*)f->data;
d->pcap_layer = *(int*)arg;
return 0;
}
static int player_set_timeref(MSFilter *f, void *arg){
PlayerData *d=(PlayerData*)f->data;
d->pcap_timeref = *(int*)arg;
return 0;
}
static int player_set_to_port(MSFilter *f, void *arg){
PlayerData *d=(PlayerData*)f->data;
d->to_port = *(unsigned*)arg;
return 0;
}
static MSFilterMethod player_methods[]={
{ MS_FILTER_GET_SAMPLE_RATE, player_get_sr},
{ MS_FILTER_SET_SAMPLE_RATE, player_set_sr},
{ MS_PCAP_FILE_PLAYER_SET_LAYER, player_set_layer},
{ MS_PCAP_FILE_PLAYER_SET_TIMEREF, player_set_timeref},
{ MS_PCAP_FILE_PLAYER_SET_TO_PORT, player_set_to_port},