summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am37
-rw-r--r--src/Makefile.in590
-rw-r--r--src/extratransmitters/rtpfaketransmitter.cpp1713
-rw-r--r--src/extratransmitters/rtpfaketransmitter.h241
-rw-r--r--src/rtcpapppacket.cpp87
-rw-r--r--src/rtcpapppacket.h127
-rw-r--r--src/rtcpbyepacket.cpp98
-rw-r--r--src/rtcpbyepacket.h135
-rw-r--r--src/rtcpcompoundpacket.cpp225
-rw-r--r--src/rtcpcompoundpacket.h106
-rw-r--r--src/rtcpcompoundpacketbuilder.cpp675
-rw-r--r--src/rtcpcompoundpacketbuilder.h383
-rw-r--r--src/rtcppacket.cpp71
-rw-r--r--src/rtcppacket.h89
-rw-r--r--src/rtcppacketbuilder.cpp736
-rw-r--r--src/rtcppacketbuilder.h224
-rw-r--r--src/rtcprrpacket.cpp94
-rw-r--r--src/rtcprrpacket.h201
-rw-r--r--src/rtcpscheduler.cpp416
-rw-r--r--src/rtcpscheduler.h183
-rw-r--r--src/rtcpsdesinfo.cpp177
-rw-r--r--src/rtcpsdesinfo.h215
-rw-r--r--src/rtcpsdespacket.cpp230
-rw-r--r--src/rtcpsdespacket.h381
-rw-r--r--src/rtcpsrpacket.cpp101
-rw-r--r--src/rtcpsrpacket.h247
-rw-r--r--src/rtcpunknownpacket.h68
-rw-r--r--src/rtpaddress.h93
-rw-r--r--src/rtpcollisionlist.cpp125
-rw-r--r--src/rtpcollisionlist.h90
-rw-r--r--src/rtpconfig.h45
-rw-r--r--src/rtpconfig_unix.h.in72
-rw-r--r--src/rtpconfig_win.h54
-rw-r--r--src/rtpdebug.cpp178
-rw-r--r--src/rtpdebug.h52
-rw-r--r--src/rtpdefines.h86
-rw-r--r--src/rtperrors.cpp229
-rw-r--r--src/rtperrors.h209
-rw-r--r--src/rtphashtable.h337
-rw-r--r--src/rtpinternalsourcedata.cpp282
-rw-r--r--src/rtpinternalsourcedata.h130
-rw-r--r--src/rtpipv4address.cpp83
-rw-r--r--src/rtpipv4address.h90
-rw-r--r--src/rtpipv4destination.h108
-rw-r--r--src/rtpipv6address.cpp108
-rw-r--r--src/rtpipv6address.h105
-rw-r--r--src/rtpipv6destination.h105
-rw-r--r--src/rtpkeyhashtable.h339
-rw-r--r--src/rtplibraryversion.cpp50
-rw-r--r--src/rtplibraryversion.h71
-rw-r--r--src/rtpmemorymanager.h247
-rw-r--r--src/rtpmemoryobject.h69
-rw-r--r--src/rtppacket.cpp344
-rw-r--r--src/rtppacket.h178
-rw-r--r--src/rtppacketbuilder.cpp268
-rw-r--r--src/rtppacketbuilder.h261
-rw-r--r--src/rtppollthread.cpp169
-rw-r--r--src/rtppollthread.h74
-rw-r--r--src/rtprandom.cpp355
-rw-r--r--src/rtprandom.h72
-rw-r--r--src/rtprawpacket.h109
-rw-r--r--src/rtpsession.cpp1477
-rw-r--r--src/rtpsession.h542
-rw-r--r--src/rtpsessionparams.cpp80
-rw-r--r--src/rtpsessionparams.h220
-rw-r--r--src/rtpsessionsources.cpp109
-rw-r--r--src/rtpsessionsources.h79
-rw-r--r--src/rtpsourcedata.cpp446
-rw-r--r--src/rtpsourcedata.h474
-rw-r--r--src/rtpsources.cpp1412
-rw-r--r--src/rtpsources.h360
-rw-r--r--src/rtpstructs.h123
-rw-r--r--src/rtptimeutilities.cpp52
-rw-r--r--src/rtptimeutilities.h319
-rw-r--r--src/rtptransmitter.h249
-rw-r--r--src/rtptypes.h37
-rw-r--r--src/rtptypes_win.h62
-rw-r--r--src/rtpudpv4transmitter.cpp1925
-rw-r--r--src/rtpudpv4transmitter.h302
-rw-r--r--src/rtpudpv6transmitter.cpp1889
-rw-r--r--src/rtpudpv6transmitter.h313
81 files changed, 23507 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..517d854
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,37 @@
+lib_LTLIBRARIES = libjrtp.la
+libjrtp_la_SOURCES = rtpdebug.cpp rtpsession.cpp rtpconfig_win.h \
+ rtperrors.cpp rtpudpv4transmitter.cpp \
+ rtcpsdesinfo.cpp rtppollthread.cpp rtppacket.cpp \
+ rtppacketbuilder.cpp rtpsessionparams.cpp \
+ rtpsources.cpp rtpinternalsourcedata.cpp \
+ rtpsourcedata.cpp rtpipv4address.cpp \
+ rtcpcompoundpacket.cpp \
+ rtcpapppacket.cpp rtcpbyepacket.cpp \
+ rtcprrpacket.cpp rtcpsdespacket.cpp \
+ rtcpsrpacket.cpp rtplibraryversion.cpp \
+ rtcppacket.cpp rtcpcompoundpacketbuilder.cpp \
+ rtprandom.cpp rtcpscheduler.cpp \
+ rtcppacketbuilder.cpp rtpsessionsources.cpp \
+ rtpcollisionlist.cpp rtpipv6address.cpp \
+ rtpudpv6transmitter.cpp rtptimeutilities.cpp \
+ extratransmitters/rtpfaketransmitter.cpp
+libjrtp_la_LDFLAGS = -release @VERSION@ @RTP_LINKLIBS@
+libjrtpinclude_HEADERS = rtcpapppacket.h rtcpbyepacket.h rtcpcompoundpacket.h \
+ rtcpcompoundpacketbuilder.h rtcppacket.h rtcppacketbuilder.h \
+ rtcprrpacket.h rtcpscheduler.h rtcpsdesinfo.h rtcpsdespacket.h \
+ rtcpsrpacket.h rtcpunknownpacket.h rtpaddress.h rtpconfig.h \
+ rtpconfig_win.h rtpdebug.h rtpdefines.h rtperrors.h rtphashtable.h \
+ rtpconfig_unix.h rtpinternalsourcedata.h rtpipv4address.h \
+ rtpipv4destination.h rtpkeyhashtable.h rtplibraryversion.h rtppacket.h \
+ rtppacketbuilder.h rtppollthread.h rtprandom.h rtprawpacket.h \
+ rtpsession.h rtpsessionparams.h rtpsourcedata.h rtpsources.h \
+ rtpstructs.h rtptimeutilities.h rtptransmitter.h \
+ rtptypes_win.h rtpudpv4transmitter.h rtpsessionsources.h \
+ rtpcollisionlist.h rtpipv6address.h rtpipv6destination.h \
+ rtpudpv6transmitter.h rtptypes.h rtptypes_unix.h \
+ rtpmemorymanager.h rtpmemoryobject.h \
+ extratransmitters/rtpfaketransmitter.h
+EXTRA_DIST = rtpconfig_unix.h.in
+libjrtpincludedir = ${includedir}/jrtplib3
+INCLUDES = @RTP_JTHREADINCLUDES@
+
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..cc8ca9f
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,590 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src
+DIST_COMMON = $(libjrtpinclude_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/rtpconfig_unix.h.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = rtpconfig_unix.h
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)" \
+ "$(DESTDIR)$(libjrtpincludedir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libjrtp_la_LIBADD =
+am_libjrtp_la_OBJECTS = rtpdebug.lo rtpsession.lo rtperrors.lo \
+ rtpudpv4transmitter.lo rtcpsdesinfo.lo rtppollthread.lo \
+ rtppacket.lo rtppacketbuilder.lo rtpsessionparams.lo \
+ rtpsources.lo rtpinternalsourcedata.lo rtpsourcedata.lo \
+ rtpipv4address.lo rtcpcompoundpacket.lo rtcpapppacket.lo \
+ rtcpbyepacket.lo rtcprrpacket.lo rtcpsdespacket.lo \
+ rtcpsrpacket.lo rtplibraryversion.lo rtcppacket.lo \
+ rtcpcompoundpacketbuilder.lo rtprandom.lo rtcpscheduler.lo \
+ rtcppacketbuilder.lo rtpsessionsources.lo rtpcollisionlist.lo \
+ rtpipv6address.lo rtpudpv6transmitter.lo rtptimeutilities.lo \
+ rtpfaketransmitter.lo
+libjrtp_la_OBJECTS = $(am_libjrtp_la_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libjrtp_la_SOURCES)
+DIST_SOURCES = $(libjrtp_la_SOURCES)
+libjrtpincludeHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(libjrtpinclude_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RTP_ENDIAN = @RTP_ENDIAN@
+RTP_FILIO = @RTP_FILIO@
+RTP_HAVE_SOCKADDR_LEN = @RTP_HAVE_SOCKADDR_LEN@
+RTP_JTHREADINCLUDES = @RTP_JTHREADINCLUDES@
+RTP_LINKLIBS = @RTP_LINKLIBS@
+RTP_SOCKIO = @RTP_SOCKIO@
+RTP_SOCKLENTYPE_UINT = @RTP_SOCKLENTYPE_UINT@
+RTP_SUPPORT_GETLOGINR = @RTP_SUPPORT_GETLOGINR@
+RTP_SUPPORT_GNUDRAND = @RTP_SUPPORT_GNUDRAND@
+RTP_SUPPORT_IFADDRS = @RTP_SUPPORT_IFADDRS@
+RTP_SUPPORT_INLINETEMPLATEPARAM = @RTP_SUPPORT_INLINETEMPLATEPARAM@
+RTP_SUPPORT_IPV4MULTICAST = @RTP_SUPPORT_IPV4MULTICAST@
+RTP_SUPPORT_IPV6 = @RTP_SUPPORT_IPV6@
+RTP_SUPPORT_IPV6MULTICAST = @RTP_SUPPORT_IPV6MULTICAST@
+RTP_SUPPORT_MEMORYMANAGEMENT = @RTP_SUPPORT_MEMORYMANAGEMENT@
+RTP_SUPPORT_PROBATION = @RTP_SUPPORT_PROBATION@
+RTP_SUPPORT_RANDR = @RTP_SUPPORT_RANDR@
+RTP_SUPPORT_SDESPRIV = @RTP_SUPPORT_SDESPRIV@
+RTP_SUPPORT_SENDAPP = @RTP_SUPPORT_SENDAPP@
+RTP_SUPPORT_THREAD = @RTP_SUPPORT_THREAD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+lib_LTLIBRARIES = libjrtp.la
+libjrtp_la_SOURCES = rtpdebug.cpp rtpsession.cpp rtpconfig_win.h \
+ rtperrors.cpp rtpudpv4transmitter.cpp \
+ rtcpsdesinfo.cpp rtppollthread.cpp rtppacket.cpp \
+ rtppacketbuilder.cpp rtpsessionparams.cpp \
+ rtpsources.cpp rtpinternalsourcedata.cpp \
+ rtpsourcedata.cpp rtpipv4address.cpp \
+ rtcpcompoundpacket.cpp \
+ rtcpapppacket.cpp rtcpbyepacket.cpp \
+ rtcprrpacket.cpp rtcpsdespacket.cpp \
+ rtcpsrpacket.cpp rtplibraryversion.cpp \
+ rtcppacket.cpp rtcpcompoundpacketbuilder.cpp \
+ rtprandom.cpp rtcpscheduler.cpp \
+ rtcppacketbuilder.cpp rtpsessionsources.cpp \
+ rtpcollisionlist.cpp rtpipv6address.cpp \
+ rtpudpv6transmitter.cpp rtptimeutilities.cpp \
+ extratransmitters/rtpfaketransmitter.cpp
+
+libjrtp_la_LDFLAGS = -release @VERSION@ @RTP_LINKLIBS@
+libjrtpinclude_HEADERS = rtcpapppacket.h rtcpbyepacket.h rtcpcompoundpacket.h \
+ rtcpcompoundpacketbuilder.h rtcppacket.h rtcppacketbuilder.h \
+ rtcprrpacket.h rtcpscheduler.h rtcpsdesinfo.h rtcpsdespacket.h \
+ rtcpsrpacket.h rtcpunknownpacket.h rtpaddress.h rtpconfig.h \
+ rtpconfig_win.h rtpdebug.h rtpdefines.h rtperrors.h rtphashtable.h \
+ rtpconfig_unix.h rtpinternalsourcedata.h rtpipv4address.h \
+ rtpipv4destination.h rtpkeyhashtable.h rtplibraryversion.h rtppacket.h \
+ rtppacketbuilder.h rtppollthread.h rtprandom.h rtprawpacket.h \
+ rtpsession.h rtpsessionparams.h rtpsourcedata.h rtpsources.h \
+ rtpstructs.h rtptimeutilities.h rtptransmitter.h \
+ rtptypes_win.h rtpudpv4transmitter.h rtpsessionsources.h \
+ rtpcollisionlist.h rtpipv6address.h rtpipv6destination.h \
+ rtpudpv6transmitter.h rtptypes.h rtptypes_unix.h \
+ rtpmemorymanager.h rtpmemoryobject.h \
+ extratransmitters/rtpfaketransmitter.h
+
+EXTRA_DIST = rtpconfig_unix.h.in
+libjrtpincludedir = ${includedir}/jrtplib3
+INCLUDES = @RTP_JTHREADINCLUDES@
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+rtpconfig_unix.h: $(top_builddir)/config.status $(srcdir)/rtpconfig_unix.h.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+ $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libjrtp.la: $(libjrtp_la_OBJECTS) $(libjrtp_la_DEPENDENCIES)
+ $(CXXLINK) -rpath $(libdir) $(libjrtp_la_LDFLAGS) $(libjrtp_la_OBJECTS) $(libjrtp_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtcpapppacket.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtcpbyepacket.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtcpcompoundpacket.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtcpcompoundpacketbuilder.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtcppacket.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtcppacketbuilder.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtcprrpacket.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtcpscheduler.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtcpsdesinfo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtcpsdespacket.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtcpsrpacket.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtpcollisionlist.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtpdebug.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtperrors.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtpfaketransmitter.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtpinternalsourcedata.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtpipv4address.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtpipv6address.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtplibraryversion.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtppacket.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtppacketbuilder.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtppollthread.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtprandom.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtpsession.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtpsessionparams.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtpsessionsources.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtpsourcedata.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtpsources.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtptimeutilities.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtpudpv4transmitter.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtpudpv6transmitter.Plo@am__quote@
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
+
+rtpfaketransmitter.lo: extratransmitters/rtpfaketransmitter.cpp
+@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT rtpfaketransmitter.lo -MD -MP -MF "$(DEPDIR)/rtpfaketransmitter.Tpo" -c -o rtpfaketransmitter.lo `test -f 'extratransmitters/rtpfaketransmitter.cpp' || echo '$(srcdir)/'`extratransmitters/rtpfaketransmitter.cpp; \
+@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/rtpfaketransmitter.Tpo" "$(DEPDIR)/rtpfaketransmitter.Plo"; else rm -f "$(DEPDIR)/rtpfaketransmitter.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='extratransmitters/rtpfaketransmitter.cpp' object='rtpfaketransmitter.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o rtpfaketransmitter.lo `test -f 'extratransmitters/rtpfaketransmitter.cpp' || echo '$(srcdir)/'`extratransmitters/rtpfaketransmitter.cpp
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-libjrtpincludeHEADERS: $(libjrtpinclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(libjrtpincludedir)" || $(mkdir_p) "$(DESTDIR)$(libjrtpincludedir)"
+ @list='$(libjrtpinclude_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(libjrtpincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(libjrtpincludedir)/$$f'"; \
+ $(libjrtpincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(libjrtpincludedir)/$$f"; \
+ done
+
+uninstall-libjrtpincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libjrtpinclude_HEADERS)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(libjrtpincludedir)/$$f'"; \
+ rm -f "$(DESTDIR)$(libjrtpincludedir)/$$f"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ $(mkdir_p) $(distdir)/extratransmitters
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libjrtpincludedir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-libjrtpincludeHEADERS
+
+install-exec-am: install-libLTLIBRARIES
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES \
+ uninstall-libjrtpincludeHEADERS
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am \
+ install-libLTLIBRARIES install-libjrtpincludeHEADERS \
+ install-man install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-info-am uninstall-libLTLIBRARIES \
+ uninstall-libjrtpincludeHEADERS
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/extratransmitters/rtpfaketransmitter.cpp b/src/extratransmitters/rtpfaketransmitter.cpp
new file mode 100644
index 0000000..33f66d2
--- /dev/null
+++ b/src/extratransmitters/rtpfaketransmitter.cpp
@@ -0,0 +1,1713 @@
+/*
+
+ This class allows for jrtp to process packets without sending them out
+ anywhere.
+ The incoming messages are handed in to jrtp through the TransmissionParams
+ and can be retreived from jrtp through the normal polling mecanisms.
+ The outgoing RTP/RTCP packets are given to jrtp through the normal
+ session->SendPacket() and those packets are handed back out to the
+ client through a callback function (packet_ready_cb).
+
+ example usage : Allows for integration of RTP into gstreamer.
+
+ THIS HAS NOT BEEN TESTED WITH THREADS SO DON'T TRY
+
+ Copyright (c) 2005 Philippe Khalaf <burger@speedy.org>
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2004 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.luc.ac.be), a research center of the "Limburgs Universitair
+ Centrum" (http://www.luc.ac.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtpfaketransmitter.h"
+
+#include "rtprawpacket.h"
+#include "rtpipv4address.h"
+#include "rtptimeutilities.h"
+#include <stdio.h>
+
+#include <sys/socket.h>
+#include <net/if.h>
+#include <string.h>
+#include <netdb.h>
+#include <unistd.h>
+
+#ifdef RTP_HAVE_SYS_FILIO
+#include <sys/filio.h>
+#endif // RTP_HAVE_SYS_FILIO
+
+#define RTPIOCTL ioctl
+
+#ifdef RTPDEBUG
+ #include <iostream>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+#define RTPFAKETRANS_MAXPACKSIZE 65535
+#define RTPFAKETRANS_IFREQBUFSIZE 8192
+
+//#define RTPFAKETRANS_IS_MCASTADDR(x) (((x)&0xF0000000) == 0xE0000000)
+
+/*#define RTPFAKETRANS_MCASTMEMBERSHIP(socket,type,mcastip,status) {\
+ struct ip_mreq mreq;\
+ \
+ mreq.imr_multiaddr.s_addr = htonl(mcastip);\
+ mreq.imr_interface.s_addr = htonl(bindIP);\
+ status = setsockopt(socket,IPPROTO_IP,type,(const char *)&mreq,sizeof(struct ip_mreq));\
+ }*/
+#ifdef RTP_SUPPORT_THREAD
+ #define MAINMUTEX_LOCK { if (threadsafe) mainmutex.Lock(); }
+ #define MAINMUTEX_UNLOCK { if (threadsafe) mainmutex.Unlock(); }
+ #define WAITMUTEX_LOCK { if (threadsafe) waitmutex.Lock(); }
+ #define WAITMUTEX_UNLOCK { if (threadsafe) waitmutex.Unlock(); }
+#else
+ #define MAINMUTEX_LOCK
+ #define MAINMUTEX_UNLOCK
+ #define WAITMUTEX_LOCK
+ #define WAITMUTEX_UNLOCK
+#endif // RTP_SUPPORT_THREAD
+
+RTPFakeTransmitter::RTPFakeTransmitter(RTPMemoryManager *mgr ) : RTPTransmitter(mgr), destinations(mgr,RTPMEM_TYPE_CLASS_DESTINATIONLISTHASHELEMENT),acceptignoreinfo(mgr,RTPMEM_TYPE_CLASS_ACCEPTIGNOREHASHELEMENT)
+{
+ created = false;
+ init = false;
+}
+
+RTPFakeTransmitter::~RTPFakeTransmitter()
+{
+ Destroy();
+}
+
+int RTPFakeTransmitter::Init(bool tsafe)
+{
+ if (init)
+ return ERR_RTP_FAKETRANS_ALREADYINIT;
+
+ // bomb out if trying to use threads
+ if (tsafe)
+ return ERR_RTP_NOTHREADSUPPORT;
+
+#ifdef RTP_SUPPORT_THREAD
+ threadsafe = tsafe;
+ if (threadsafe)
+ {
+ int status;
+
+ status = mainmutex.Init();
+ if (status < 0)
+ return ERR_RTP_FAKETRANS_CANTINITMUTEX;
+ status = waitmutex.Init();
+ if (status < 0)
+ return ERR_RTP_FAKETRANS_CANTINITMUTEX;
+ }
+#else
+ if (tsafe)
+ return ERR_RTP_NOTHREADSUPPORT;
+#endif // RTP_SUPPORT_THREAD
+
+ init = true;
+ return 0;
+}
+
+int RTPFakeTransmitter::Create(size_t maximumpacketsize,const RTPTransmissionParams *transparams)
+{
+// struct sockaddr_in addr;
+// int status;
+
+ if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_ALREADYCREATED;
+ }
+
+ // Obtain transmission parameters
+
+ if (transparams == 0)
+ params = RTPNew(GetMemoryManager(),RTPMEM_TYPE_OTHER) RTPFakeTransmissionParams;
+ else
+ {
+ if (transparams->GetTransmissionProtocol() != RTPTransmitter::UserDefinedProto)
+ return ERR_RTP_FAKETRANS_ILLEGALPARAMETERS;
+ params = (RTPFakeTransmissionParams *)transparams;
+ }
+
+ // Check if portbase is even
+ //if (params->GetPortbase()%2 != 0)
+ //{
+ // MAINMUTEX_UNLOCK
+ // return ERR_RTP_FAKETRANS_PORTBASENOTEVEN;
+ //}
+
+ // Try to obtain local IP addresses
+
+ localIPs = params->GetLocalIPList();
+ if (localIPs.empty()) // User did not provide list of local IP addresses, calculate them
+ {
+ int status;
+
+ if ((status = CreateLocalIPList()) < 0)
+ {
+ MAINMUTEX_UNLOCK
+ return status;
+ }
+#ifdef RTPDEBUG
+ std::cout << "Found these local IP addresses:" << std::endl;
+
+ std::list<uint32_t>::const_iterator it;
+
+ for (it = localIPs.begin() ; it != localIPs.end() ; it++)
+ {
+ RTPIPv4Address a(*it);
+
+ std::cout << a.GetAddressString() << std::endl;
+ }
+#endif // RTPDEBUG
+ }
+
+//#ifdef RTP_SUPPORT_IPV4MULTICAST
+// if (SetMulticastTTL(params->GetMulticastTTL()))
+// supportsmulticasting = true;
+// else
+// supportsmulticasting = false;
+//#else // no multicast support enabled
+ supportsmulticasting = false;
+//#endif // RTP_SUPPORT_IPV4MULTICAST
+
+ if (maximumpacketsize > RTPFAKETRANS_MAXPACKSIZE)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_SPECIFIEDSIZETOOBIG;
+ }
+
+ maxpacksize = maximumpacketsize;
+ portbase = params->GetPortbase();
+ multicastTTL = params->GetMulticastTTL();
+ receivemode = RTPTransmitter::AcceptAll;
+
+ localhostname = 0;
+ localhostnamelength = 0;
+
+ waitingfordata = false;
+ created = true;
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+void RTPFakeTransmitter::Destroy()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK;
+ return;
+ }
+
+ if (localhostname)
+ {
+ RTPDeleteByteArray(localhostname,GetMemoryManager());
+ localhostname = 0;
+ localhostnamelength = 0;
+ }
+
+ destinations.Clear();
+#ifdef RTP_SUPPORT_IPV4MULTICAST
+// multicastgroups.Clear();
+#endif // RTP_SUPPORT_IPV4MULTICAST
+ FlushPackets();
+ ClearAcceptIgnoreInfo();
+ localIPs.clear();
+ created = false;
+ RTPDelete(params,GetMemoryManager());
+
+ MAINMUTEX_UNLOCK
+}
+
+RTPTransmissionInfo *RTPFakeTransmitter::GetTransmissionInfo()
+{
+ if (!init)
+ return 0;
+
+ MAINMUTEX_LOCK
+ RTPTransmissionInfo *tinf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPTRANSMISSIONINFO) RTPFakeTransmissionInfo(localIPs, params);
+ MAINMUTEX_UNLOCK
+ return tinf;
+}
+
+int RTPFakeTransmitter::GetLocalHostName(uint8_t *buffer,size_t *bufferlength)
+{
+ if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+
+ if (localhostname == 0)
+ {
+ if (localIPs.empty())
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOLOCALIPS;
+ }
+
+ std::list<uint32_t>::const_iterator it;
+ std::list<std::string> hostnames;
+
+ for (it = localIPs.begin() ; it != localIPs.end() ; it++)
+ {
+ struct hostent *he;
+ uint8_t addr[4];
+ uint32_t ip = (*it);
+
+ addr[0] = (uint8_t)((ip>>24)&0xFF);
+ addr[1] = (uint8_t)((ip>>16)&0xFF);
+ addr[2] = (uint8_t)((ip>>8)&0xFF);
+ addr[3] = (uint8_t)(ip&0xFF);
+ he = gethostbyaddr((char *)addr,4,AF_INET);
+ if (he != 0)
+ {
+ std::string hname = std::string(he->h_name);
+ hostnames.push_back(hname);
+ }
+ }
+
+ bool found = false;
+
+ if (!hostnames.empty()) // try to select the most appropriate hostname
+ {
+ std::list<std::string>::const_iterator it;
+
+ for (it = hostnames.begin() ; !found && it != hostnames.end() ; it++)
+ {
+ if ((*it).find('.') != std::string::npos)
+ {
+ found = true;
+ localhostnamelength = (*it).length();
+ localhostname = RTPNew(GetMemoryManager(),RTPMEM_TYPE_OTHER) uint8_t [localhostnamelength+1];
+ if (localhostname == 0)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_OUTOFMEM;
+ }
+ memcpy(localhostname,(*it).c_str(),localhostnamelength);
+ localhostname[localhostnamelength] = 0;
+ }
+ }
+ }
+
+ if (!found) // use an IP address
+ {
+ uint32_t ip;
+ int len;
+ char str[16];
+
+ it = localIPs.begin();
+ ip = (*it);
+
+ snprintf(str,16,"%d.%d.%d.%d",(int)((ip>>24)&0xFF),(int)((ip>>16)&0xFF),(int)((ip>>8)&0xFF),(int)(ip&0xFF));
+ len = strlen(str);
+
+ localhostnamelength = len;
+ localhostname = RTPNew(GetMemoryManager(),RTPMEM_TYPE_OTHER) uint8_t [localhostnamelength + 1];
+ if (localhostname == 0)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_OUTOFMEM;
+ }
+ memcpy(localhostname,str,localhostnamelength);
+ localhostname[localhostnamelength] = 0;
+ }
+ }
+
+ if ((*bufferlength) < localhostnamelength)
+ {
+ *bufferlength = localhostnamelength; // tell the application the required size of the buffer
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_TRANS_BUFFERLENGTHTOOSMALL;
+ }
+
+ memcpy(buffer,localhostname,localhostnamelength);
+ *bufferlength = localhostnamelength;
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+bool RTPFakeTransmitter::ComesFromThisTransmitter(const RTPAddress *addr)
+{
+ if (!init)
+ return false;
+
+ if (addr == 0)
+ return false;
+
+ MAINMUTEX_LOCK
+
+ bool v;
+
+ if (created && addr->GetAddressType() == RTPAddress::IPv4Address)
+ {
+ const RTPIPv4Address *addr2 = (const RTPIPv4Address *)addr;
+ bool found = false;
+ std::list<uint32_t>::const_iterator it;
+
+ it = localIPs.begin();
+ while (!found && it != localIPs.end())
+ {
+ if (addr2->GetIP() == *it)
+ found = true;
+ else
+ ++it;
+ }
+
+ if (!found)
+ v = false;
+ else
+ {
+ if (addr2->GetPort() == params->GetPortbase()) // check for RTP port
+ v = true;
+ else if (addr2->GetPort() == (params->GetPortbase()+1)) // check for RTCP port
+ v = true;
+ else
+ v = false;
+ }
+ }
+ else
+ v = false;
+
+ MAINMUTEX_UNLOCK
+ return v;
+}
+
+int RTPFakeTransmitter::Poll()
+{
+ if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ int status;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+ status = FakePoll(); // poll RTP socket
+ params->SetCurrentData(NULL);
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPFakeTransmitter::WaitForIncomingData(const RTPTime &delay,bool *dataavailable)
+{
+/* if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ fd_set fdset;
+ struct timeval tv;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+ if (waitingfordata)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_ALREADYWAITING;
+ }
+
+ FD_ZERO(&fdset);
+ FD_SET(rtpsock,&fdset);
+ FD_SET(rtcpsock,&fdset);
+ FD_SET(abortdesc[0],&fdset);
+ tv.tv_sec = delay.GetSeconds();
+ tv.tv_usec = delay.GetMicroSeconds();
+
+ waitingfordata = true;
+
+ WAITMUTEX_LOCK
+ MAINMUTEX_UNLOCK
+
+ if (select(FD_SETSIZE,&fdset,0,0,&tv) < 0)
+ {
+ MAINMUTEX_LOCK
+ waitingfordata = false;
+ MAINMUTEX_UNLOCK
+ WAITMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_ERRORINSELECT;
+ }
+
+ MAINMUTEX_LOCK
+ waitingfordata = false;
+ if (!created) // destroy called
+ {
+ MAINMUTEX_UNLOCK;
+ WAITMUTEX_UNLOCK
+ return 0;
+ }
+
+ // if aborted, read from abort buffer
+ if (FD_ISSET(abortdesc[0],&fdset))
+ {
+#ifdef WIN32
+ char buf[1];
+
+ recv(abortdesc[0],buf,1,0);
+#else
+ unsigned char buf[1];
+
+ read(abortdesc[0],buf,1);
+#endif // WIN32
+ }
+
+ MAINMUTEX_UNLOCK
+ WAITMUTEX_UNLOCK
+ return 0;*/
+ return ERR_RTP_FAKETRANS_WAITNOTIMPLEMENTED;
+}
+
+int RTPFakeTransmitter::AbortWait()
+{
+/* if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+ if (!waitingfordata)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTWAITING;
+ }
+
+ AbortWaitInternal();
+
+ MAINMUTEX_UNLOCK
+ return 0;*/
+ return 0;
+}
+
+int RTPFakeTransmitter::SendRTPData(const void *data,size_t len)
+{
+ if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+ if (len > maxpacksize)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_SPECIFIEDSIZETOOBIG;
+ }
+
+
+ destinations.GotoFirstElement();
+ // send to each destination
+ while (destinations.HasCurrentElement())
+ {
+ (*params->GetPacketReadyCB())(params->GetPacketReadyCBData(), (uint8_t*)data, len,
+ destinations.GetCurrentElement().GetIP_NBO(),
+ destinations.GetCurrentElement().GetRTPPort_NBO(),
+ 1);
+ destinations.GotoNextElement();
+ }
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPFakeTransmitter::SendRTCPData(const void *data,size_t len)
+{
+ if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+ if (len > maxpacksize)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_SPECIFIEDSIZETOOBIG;
+ }
+
+ destinations.GotoFirstElement();
+ // send to each destination
+ while (destinations.HasCurrentElement())
+ {
+ (*params->GetPacketReadyCB())(params->GetPacketReadyCBData(), (uint8_t*)data, len,
+ destinations.GetCurrentElement().GetIP_NBO(),
+ destinations.GetCurrentElement().GetRTCPPort_NBO(),
+ 0);
+ destinations.GotoNextElement();
+ }
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPFakeTransmitter::AddDestination(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_INVALIDADDRESSTYPE;
+ }
+
+ RTPIPv4Address &address = (RTPIPv4Address &)addr;
+ RTPIPv4Destination dest(address.GetIP(),address.GetPort());
+ int status = destinations.AddElement(dest);
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPFakeTransmitter::DeleteDestination(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_INVALIDADDRESSTYPE;
+ }
+
+ RTPIPv4Address &address = (RTPIPv4Address &)addr;
+ RTPIPv4Destination dest(address.GetIP(),address.GetPort());
+ int status = destinations.DeleteElement(dest);
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+void RTPFakeTransmitter::ClearDestinations()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created)
+ destinations.Clear();
+ MAINMUTEX_UNLOCK
+}
+
+bool RTPFakeTransmitter::SupportsMulticasting()
+{
+ if (!init)
+ return false;
+
+ MAINMUTEX_LOCK
+
+ bool v;
+
+ if (!created)
+ v = false;
+ else
+ v = supportsmulticasting;
+
+ MAINMUTEX_UNLOCK
+ return v;
+}
+
+#ifdef RTP_SUPPORT_IPV4MULTICAST
+
+int RTPFakeTransmitter::JoinMulticastGroup(const RTPAddress &addr)
+{
+// hrrm wonder how will manage to get multicast info thru to the UDPSINK
+/* if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_INVALIDADDRESSTYPE;
+ }
+
+ const RTPIPv4Address &address = (const RTPIPv4Address &)addr;
+ uint32_t mcastIP = address.GetIP();
+
+ if (!RTPFakeTRANS_IS_MCASTADDR(mcastIP))
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTAMULTICASTADDRESS;
+ }
+
+ status = multicastgroups.AddElement(mcastIP);
+ if (status >= 0)
+ {
+ RTPFakeTRANS_MCASTMEMBERSHIP(rtpsock,IP_ADD_MEMBERSHIP,mcastIP,status);
+ if (status != 0)
+ {
+ multicastgroups.DeleteElement(mcastIP);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_COULDNTJOINMULTICASTGROUP;
+ }
+ RTPFakeTRANS_MCASTMEMBERSHIP(rtcpsock,IP_ADD_MEMBERSHIP,mcastIP,status);
+ if (status != 0)
+ {
+ RTPFakeTRANS_MCASTMEMBERSHIP(rtpsock,IP_DROP_MEMBERSHIP,mcastIP,status);
+ multicastgroups.DeleteElement(mcastIP);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_COULDNTJOINMULTICASTGROUP;
+ }
+ }
+ MAINMUTEX_UNLOCK
+ return status;*/
+ return ERR_RTP_FAKETRANS_NOMULTICASTSUPPORT;
+}
+
+int RTPFakeTransmitter::LeaveMulticastGroup(const RTPAddress &addr)
+{
+ /*
+ if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_INVALIDADDRESSTYPE;
+ }
+
+ const RTPIPv4Address &address = (const RTPIPv4Address &)addr;
+ uint32_t mcastIP = address.GetIP();
+
+ if (!RTPFakeTRANS_IS_MCASTADDR(mcastIP))
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTAMULTICASTADDRESS;
+ }
+
+ status = multicastgroups.DeleteElement(mcastIP);
+ if (status >= 0)
+ {
+ RTPFakeTRANS_MCASTMEMBERSHIP(rtpsock,IP_DROP_MEMBERSHIP,mcastIP,status);
+ RTPFakeTRANS_MCASTMEMBERSHIP(rtcpsock,IP_DROP_MEMBERSHIP,mcastIP,status);
+ status = 0;
+ }
+
+ MAINMUTEX_UNLOCK
+ return status;
+ */
+ return ERR_RTP_FAKETRANS_NOMULTICASTSUPPORT;
+}
+
+void RTPFakeTransmitter::LeaveAllMulticastGroups()
+{
+/* if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created)
+ {
+ multicastgroups.GotoFirstElement();
+ while (multicastgroups.HasCurrentElement())
+ {
+ uint32_t mcastIP;
+ int status = 0;
+
+ mcastIP = multicastgroups.GetCurrentElement();
+ RTPFakeTRANS_MCASTMEMBERSHIP(rtpsock,IP_DROP_MEMBERSHIP,mcastIP,status);
+ RTPFakeTRANS_MCASTMEMBERSHIP(rtcpsock,IP_DROP_MEMBERSHIP,mcastIP,status);
+ multicastgroups.GotoNextElement();
+ }
+ multicastgroups.Clear();
+ }
+ MAINMUTEX_UNLOCK*/
+}
+
+#else // no multicast support
+
+int RTPFakeTransmitter::JoinMulticastGroup(const RTPAddress &addr)
+{
+ return ERR_RTP_FAKETRANS_NOMULTICASTSUPPORT;
+}
+
+int RTPFakeTransmitter::LeaveMulticastGroup(const RTPAddress &addr)
+{
+ return ERR_RTP_FAKETRANS_NOMULTICASTSUPPORT;
+}
+
+void RTPFakeTransmitter::LeaveAllMulticastGroups()
+{
+}
+
+#endif // RTP_SUPPORT_IPV4MULTICAST
+
+int RTPFakeTransmitter::SetReceiveMode(RTPTransmitter::ReceiveMode m)
+{
+ if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+ if (m != receivemode)
+ {
+ receivemode = m;
+ acceptignoreinfo.Clear();
+ }
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPFakeTransmitter::AddToIgnoreList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::IgnoreSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv4Address &address = (const RTPIPv4Address &)addr;
+ status = ProcessAddAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPFakeTransmitter::DeleteFromIgnoreList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::IgnoreSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv4Address &address = (const RTPIPv4Address &)addr;
+ status = ProcessDeleteAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+void RTPFakeTransmitter::ClearIgnoreList()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created && receivemode == RTPTransmitter::IgnoreSome)
+ ClearAcceptIgnoreInfo();
+ MAINMUTEX_UNLOCK
+}
+
+int RTPFakeTransmitter::AddToAcceptList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::AcceptSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv4Address &address = (const RTPIPv4Address &)addr;
+ status = ProcessAddAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPFakeTransmitter::DeleteFromAcceptList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::AcceptSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv4Address &address = (const RTPIPv4Address &)addr;
+ status = ProcessDeleteAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+void RTPFakeTransmitter::ClearAcceptList()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created && receivemode == RTPTransmitter::AcceptSome)
+ ClearAcceptIgnoreInfo();
+ MAINMUTEX_UNLOCK
+}
+
+int RTPFakeTransmitter::SetMaximumPacketSize(size_t s)
+{
+ if (!init)
+ return ERR_RTP_FAKETRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_NOTCREATED;
+ }
+ if (s > RTPFAKETRANS_MAXPACKSIZE)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_FAKETRANS_SPECIFIEDSIZETOOBIG;
+ }
+ maxpacksize = s;
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+bool RTPFakeTransmitter::NewDataAvailable()
+{
+ if (!init)
+ return false;
+
+ MAINMUTEX_LOCK
+
+ bool v;
+
+ if (!created)
+ v = false;
+ else
+ {
+ if (rawpacketlist.empty())
+ v = false;
+ else
+ v = true;
+ }
+
+ MAINMUTEX_UNLOCK
+ return v;
+}
+
+RTPRawPacket *RTPFakeTransmitter::GetNextPacket()
+{
+ if (!init)
+ return 0;
+
+ MAINMUTEX_LOCK
+
+ RTPRawPacket *p;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return 0;
+ }
+ if (rawpacketlist.empty())
+ {
+ MAINMUTEX_UNLOCK
+ return 0;
+ }
+
+ p = *(rawpacketlist.begin());
+ rawpacketlist.pop_front();
+
+ MAINMUTEX_UNLOCK
+ return p;
+}
+
+// Here the private functions start...
+
+#ifdef RTP_SUPPORT_IPV4MULTICAST
+bool RTPFakeTransmitter::SetMulticastTTL(uint8_t ttl)
+{
+/* int ttl2,status;
+
+ ttl2 = (int)ttl;
+ status = setsockopt(rtpsock,IPPROTO_IP,IP_MULTICAST_TTL,(const char *)&ttl2,sizeof(int));
+ if (status != 0)
+ return false;
+ status = setsockopt(rtcpsock,IPPROTO_IP,IP_MULTICAST_TTL,(const char *)&ttl2,sizeof(int));
+ if (status != 0)
+ return false;
+ return true;*/
+ return true;
+}
+#endif // RTP_SUPPORT_IPV4MULTICAST
+
+void RTPFakeTransmitter::FlushPackets()
+{
+ std::list<RTPRawPacket*>::const_iterator it;
+
+ for (it = rawpacketlist.begin() ; it != rawpacketlist.end() ; ++it)
+ RTPDelete(*it,GetMemoryManager());
+ rawpacketlist.clear();
+}
+
+int RTPFakeTransmitter::FakePoll()
+{
+ uint8_t *data = NULL;
+ int data_len = 0;
+ uint32_t sourceaddr;
+ uint16_t sourceport;
+ bool rtp;
+ bool acceptdata;
+
+ RTPTime curtime = RTPTime::CurrentTime();
+
+ data = params->GetCurrentData();
+ data_len = params->GetCurrentDataLen();
+ rtp = params->GetCurrentDataType();
+ sourceaddr = params->GetCurrentDataAddr();
+ sourceport = params->GetCurrentDataPort();
+ // lets make sure we got something
+ if (data == NULL || data_len <= 0)
+ {
+ return 0;
+ }
+
+ // let's make a RTPIPv4Address
+ RTPIPv4Address *addr = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPADDRESS) RTPIPv4Address(sourceaddr, sourceport);
+ if (addr == 0)
+ {
+ return ERR_RTP_OUTOFMEM;
+ }
+
+ // ok we got the src addr, now this should be the actual packet
+ uint8_t *datacopy;
+ datacopy = RTPNew(GetMemoryManager(),(rtp)?RTPMEM_TYPE_BUFFER_RECEIVEDRTPPACKET:RTPMEM_TYPE_BUFFER_RECEIVEDRTCPPACKET) uint8_t[data_len];
+ if (datacopy == 0)
+ {
+ RTPDelete(addr,GetMemoryManager());
+ return ERR_RTP_OUTOFMEM;
+ }
+ memcpy(datacopy, data, data_len);
+
+ // got data, process it
+ if (receivemode == RTPTransmitter::AcceptAll)
+ acceptdata = true;
+ else
+ acceptdata = ShouldAcceptData(addr->GetIP(),addr->GetPort());
+
+ if (acceptdata)
+ {
+ // adding packet to queue
+ RTPRawPacket *pack;
+
+ pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET) RTPRawPacket(datacopy,data_len,addr,curtime,rtp,GetMemoryManager());
+
+ if (pack == 0)
+ {
+ RTPDelete(addr,GetMemoryManager());
+ return ERR_RTP_OUTOFMEM;
+ }
+ rawpacketlist.push_back(pack);
+ }
+ return 0;
+}
+
+int RTPFakeTransmitter::ProcessAddAcceptIgnoreEntry(uint32_t ip,uint16_t port)
+{
+ acceptignoreinfo.GotoElement(ip);
+ if (acceptignoreinfo.HasCurrentElement()) // An entry for this IP address already exists
+ {
+ PortInfo *portinf = acceptignoreinfo.GetCurrentElement();
+
+ if (port == 0) // select all ports
+ {
+ portinf->all = true;
+ portinf->portlist.clear();
+ }
+ else if (!portinf->all)
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = portinf->portlist.begin();
+ end = portinf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == port) // already in list
+ return 0;
+ }
+ portinf->portlist.push_front(port);
+ }
+ }
+ else // got to create an entry for this IP address
+ {
+ PortInfo *portinf;
+ int status;
+
+ portinf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_ACCEPTIGNOREPORTINFO) PortInfo();
+ if (port == 0) // select all ports
+ portinf->all = true;
+ else
+ portinf->portlist.push_front(port);
+
+ status = acceptignoreinfo.AddElement(ip,portinf);
+ if (status < 0)
+ {
+ RTPDelete(portinf,GetMemoryManager());
+ return status;
+ }
+ }
+
+ return 0;
+}
+
+void RTPFakeTransmitter::ClearAcceptIgnoreInfo()
+{
+ acceptignoreinfo.GotoFirstElement();
+ while (acceptignoreinfo.HasCurrentElement())
+ {
+ PortInfo *inf;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ RTPDelete(inf,GetMemoryManager());
+ acceptignoreinfo.GotoNextElement();
+ }
+ acceptignoreinfo.Clear();
+}
+
+int RTPFakeTransmitter::ProcessDeleteAcceptIgnoreEntry(uint32_t ip,uint16_t port)
+{
+ acceptignoreinfo.GotoElement(ip);
+ if (!acceptignoreinfo.HasCurrentElement())
+ return ERR_RTP_FAKETRANS_NOSUCHENTRY;
+
+ PortInfo *inf;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ if (port == 0) // delete all entries
+ {
+ inf->all = false;
+ inf->portlist.clear();
+ }
+ else // a specific port was selected
+ {
+ if (inf->all) // currently, all ports are selected. Add the one to remove to the list
+ {
+ // we have to check if the list doesn't contain the port already
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == port) // already in list: this means we already deleted the entry
+ return ERR_RTP_FAKETRANS_NOSUCHENTRY;
+ }
+ inf->portlist.push_front(port);
+ }
+ else // check if we can find the port in the list
+ {
+ std::list<uint16_t>::iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; ++it)
+ {
+ if (*it == port) // found it!
+ {
+ inf->portlist.erase(it);
+ return 0;
+ }
+ }
+ // didn't find it
+ return ERR_RTP_FAKETRANS_NOSUCHENTRY;
+ }
+ }
+ return 0;
+}
+
+bool RTPFakeTransmitter::ShouldAcceptData(uint32_t srcip,uint16_t srcport)
+{
+ if (receivemode == RTPTransmitter::AcceptSome)
+ {
+ PortInfo *inf;
+
+ acceptignoreinfo.GotoElement(srcip);
+ if (!acceptignoreinfo.HasCurrentElement())
+ return false;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ if (!inf->all) // only accept the ones in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return true;
+ }
+ return false;
+ }
+ else // accept all, except the ones in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return false;
+ }
+ return true;
+ }
+ }
+ else // IgnoreSome
+ {
+ PortInfo *inf;
+
+ acceptignoreinfo.GotoElement(srcip);
+ if (!acceptignoreinfo.HasCurrentElement())
+ return true;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ if (!inf->all) // ignore the ports in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return false;
+ }
+ return true;
+ }
+ else // ignore all, except the ones in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return true;
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
+#ifdef WIN32
+
+int RTPFakeTransmitter::CreateAbortDescriptors()
+{
+ // no need for these no more
+/*
+ SOCKET listensock;
+ int size;
+ struct sockaddr_in addr;
+
+ listensock = socket(PF_INET,SOCK_STREAM,0);
+ if (listensock == RTPSOCKERR)
+ return ERR_RTP_FAKETRANS_CANTCREATEABORTDESCRIPTORS;
+
+ memset(&addr,0,sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ if (bind(listensock,(struct sockaddr *)&addr,sizeof(struct sockaddr_in)) != 0)
+ {
+ RTPCLOSE(listensock);
+ return ERR_RTP_FAKETRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in));
+ size = sizeof(struct sockaddr_in);
+ if (getsockname(listensock,(struct sockaddr*)&addr,&size) != 0)
+ {
+ RTPCLOSE(listensock);
+ return ERR_RTP_FAKETRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ unsigned short connectport = ntohs(addr.sin_port);
+
+ abortdesc[0] = socket(PF_INET,SOCK_STREAM,0);
+ if (abortdesc[0] == RTPSOCKERR)
+ {
+ RTPCLOSE(listensock);
+ return ERR_RTP_FAKETRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ if (bind(abortdesc[0],(struct sockaddr *)&addr,sizeof(struct sockaddr_in)) != 0)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_FAKETRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ if (listen(listensock,1) != 0)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_FAKETRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ addr.sin_port = htons(connectport);
+
+ if (connect(abortdesc[0],(struct sockaddr *)&addr,sizeof(struct sockaddr_in)) != 0)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_FAKETRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in));
+ size = sizeof(struct sockaddr_in);
+ abortdesc[1] = accept(listensock,(struct sockaddr *)&addr,&size);
+ if (abortdesc[1] == RTPSOCKERR)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_FAKETRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ // okay, got the connection, close the listening socket
+
+ RTPCLOSE(listensock);
+ return 0;*/
+}
+
+void RTPFakeTransmitter::DestroyAbortDescriptors()
+{
+// RTPCLOSE(abortdesc[0]);
+// RTPCLOSE(abortdesc[1]);
+}
+
+#else // in a non winsock environment we can use pipes
+
+int RTPFakeTransmitter::CreateAbortDescriptors()
+{
+// if (pipe(abortdesc) < 0)
+// return ERR_RTP_FAKETRANS_CANTCREATEPIPE;
+// return 0;
+ return 0;
+}
+
+void RTPFakeTransmitter::DestroyAbortDescriptors()
+{
+// close(abortdesc[0]);
+// close(abortdesc[1]);
+}
+
+#endif // WIN32
+
+int RTPFakeTransmitter::CreateLocalIPList()
+{
+ // first try to obtain the list from the network interface info
+
+ if (!GetLocalIPList_Interfaces())
+ {
+ // If this fails, we'll have to depend on DNS info
+ GetLocalIPList_DNS();
+ }
+ AddLoopbackAddress();
+ return 0;
+}
+
+//#ifdef WIN32
+
+bool RTPFakeTransmitter::GetLocalIPList_Interfaces()
+{
+ // REMINDER: got to find out how to do this
+ return false;
+}
+/*
+#else // use ioctl
+
+bool RTPFakeTransmitter::GetLocalIPList_Interfaces()
+{
+ int status;
+ char buffer[RTPFakeTRANS_IFREQBUFSIZE];
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ struct sockaddr *sa;
+ char *startptr,*endptr;
+ int remlen;
+
+ ifc.ifc_len = RTPFakeTRANS_IFREQBUFSIZE;
+ ifc.ifc_buf = buffer;
+ status = ioctl(rtpsock,SIOCGIFCONF,&ifc);
+ if (status < 0)
+ return false;
+
+ startptr = (char *)ifc.ifc_req;
+ endptr = startptr + ifc.ifc_len;
+ remlen = ifc.ifc_len;
+ while((startptr < endptr) && remlen >= (int)sizeof(struct ifreq))
+ {
+ ifr = (struct ifreq *)startptr;
+ sa = &(ifr->ifr_addr);
+#ifdef RTP_HAVE_SOCKADDR_LEN
+ if (sa->sa_len <= sizeof(struct sockaddr))
+ {
+ if (sa->sa_len == sizeof(struct sockaddr_in) && sa->sa_family == PF_INET)
+ {
+ uint32_t ip;
+ struct sockaddr_in *addr = (struct sockaddr_in *)sa;
+
+ ip = ntohl(addr->sin_addr.s_addr);
+ localIPs.push_back(ip);
+ }
+ remlen -= sizeof(struct ifreq);
+ startptr += sizeof(struct ifreq);
+ }
+ else
+ {
+ int l = sa->sa_len-sizeof(struct sockaddr)+sizeof(struct ifreq);
+
+ remlen -= l;
+ startptr += l;
+ }
+#else // don't have sa_len in struct sockaddr
+ if (sa->sa_family == PF_INET)
+ {
+ uint32_t ip;
+ struct sockaddr_in *addr = (struct sockaddr_in *)sa;
+
+ ip = ntohl(addr->sin_addr.s_addr);
+ localIPs.push_back(ip);
+ }
+ remlen -= sizeof(struct ifreq);
+ startptr += sizeof(struct ifreq);
+
+#endif // RTP_HAVE_SOCKADDR_LEN
+ }
+
+ if (localIPs.empty())
+ return false;
+ return true;
+}
+
+#endif // WIN32
+*/
+void RTPFakeTransmitter::GetLocalIPList_DNS()
+{
+ struct hostent *he;
+ char name[1024];
+ uint32_t ip;
+ bool done;
+ int i,j;
+
+ gethostname(name,1023);
+ name[1023] = 0;
+ he = gethostbyname(name);
+ if (he == 0)
+ return;
+
+ ip = 0;
+ i = 0;
+ done = false;
+ while (!done)
+ {
+ if (he->h_addr_list[i] == NULL)
+ done = true;
+ else
+ {
+ ip = 0;
+ for (j = 0 ; j < 4 ; j++)
+ ip |= ((uint32_t)((unsigned char)he->h_addr_list[i][j])<<((3-j)*8));
+ localIPs.push_back(ip);
+ i++;
+ }
+ }
+}
+
+void RTPFakeTransmitter::AbortWaitInternal()
+{
+/*#ifdef WIN32
+ send(abortdesc[1],"*",1,0);
+#else
+ write(abortdesc[1],"*",1);
+#endif // WIN32*/
+}
+
+void RTPFakeTransmitter::AddLoopbackAddress()
+{
+ uint32_t loopbackaddr = (((uint32_t)127)<<24)|((uint32_t)1);
+ std::list<uint32_t>::const_iterator it;
+ bool found = false;
+
+ for (it = localIPs.begin() ; !found && it != localIPs.end() ; it++)
+ {
+ if (*it == loopbackaddr)
+ found = true;
+ }
+
+ if (!found)
+ localIPs.push_back(loopbackaddr);
+}
+
+#ifdef RTPDEBUG
+void RTPFakeTransmitter::Dump()
+{
+ if (!init)
+ std::cout << "Not initialized" << std::endl;
+ else
+ {
+ MAINMUTEX_LOCK
+
+ if (!created)
+ std::cout << "Not created" << std::endl;
+ else
+ {
+ char str[16];
+ uint32_t ip;
+ std::list<uint32_t>::const_iterator it;
+
+ std::cout << "Portbase: " << params->GetPortbase() << std::endl;
+ std::cout << "Local IP addresses:" << std::endl;
+ for (it = localIPs.begin() ; it != localIPs.end() ; it++)
+ {
+ ip = (*it);
+ snprintf(str,16,"%d.%d.%d.%d",(int)((ip>>24)&0xFF),(int)((ip>>16)&0xFF),(int)((ip>>8)&0xFF),(int)(ip&0xFF));
+ std::cout << " " << str << std::endl;
+ }
+// std::cout << "Multicast TTL: " << (int)multicastTTL << std::endl;
+ std::cout << "Receive mode: ";
+ switch (receivemode)
+ {
+ case RTPTransmitter::AcceptAll:
+ std::cout << "Accept all";
+ break;
+ case RTPTransmitter::AcceptSome:
+ std::cout << "Accept some";
+ break;
+ case RTPTransmitter::IgnoreSome:
+ std::cout << "Ignore some";
+ }
+ std::cout << std::endl;
+ if (receivemode != RTPTransmitter::AcceptAll)
+ {
+ acceptignoreinfo.GotoFirstElement();
+ while(acceptignoreinfo.HasCurrentElement())
+ {
+ ip = acceptignoreinfo.GetCurrentKey();
+ snprintf(str,16,"%d.%d.%d.%d",(int)((ip>>24)&0xFF),(int)((ip>>16)&0xFF),(int)((ip>>8)&0xFF),(int)(ip&0xFF));
+ PortInfo *pinfo = acceptignoreinfo.GetCurrentElement();
+ std::cout << " " << str << ": ";
+ if (pinfo->all)
+ {
+ std::cout << "All ports";
+ if (!pinfo->portlist.empty())
+ std::cout << ", except ";
+ }
+
+ std::list<uint16_t>::const_iterator it;
+
+ for (it = pinfo->portlist.begin() ; it != pinfo->portlist.end() ; )
+ {
+ std::cout << (*it);
+ it++;
+ if (it != pinfo->portlist.end())
+ std::cout << ", ";
+ }
+ std::cout << std::endl;
+ }
+ }
+
+ std::cout << "Local host name: ";
+ if (localhostname == 0)
+ std::cout << "Not set";
+ else
+ std::cout << localhostname;
+ std::cout << std::endl;
+
+ std::cout << "List of destinations: ";
+ destinations.GotoFirstElement();
+ if (destinations.HasCurrentElement())
+ {
+ std::cout << std::endl;
+ do
+ {
+ std::cout << " " << destinations.GetCurrentElement().GetDestinationString() << std::endl;
+ destinations.GotoNextElement();
+ } while (destinations.HasCurrentElement());
+ }
+ else
+ std::cout << "Empty" << std::endl;
+
+ std::cout << "Supports multicasting: " << ((supportsmulticasting)?"Yes":"No") << std::endl;
+#ifdef RTP_SUPPORT_IPV4MULTICAST
+/* std::cout << "List of multicast groups: ";
+ multicastgroups.GotoFirstElement();
+ if (multicastgroups.HasCurrentElement())
+ {
+ std::cout << std::endl;
+ do
+ {
+ ip = multicastgroups.GetCurrentElement();
+ snprintf(str,16,"%d.%d.%d.%d",(int)((ip>>24)&0xFF),(int)((ip>>16)&0xFF),(int)((ip>>8)&0xFF),(int)(ip&0xFF));
+ std::cout << " " << str << std::endl;
+ multicastgroups.GotoNextElement();
+ } while (multicastgroups.HasCurrentElement());
+ }
+ else
+ std::cout << "Empty" << std::endl;*/
+#endif // RTP_SUPPORT_IPV4MULTICAST
+
+ std::cout << "Number of raw packets in queue: " << rawpacketlist.size() << std::endl;
+ std::cout << "Maximum allowed packet size: " << maxpacksize << std::endl;
+ }
+
+ MAINMUTEX_UNLOCK
+ }
+}
+#endif // RTPDEBUG
diff --git a/src/extratransmitters/rtpfaketransmitter.h b/src/extratransmitters/rtpfaketransmitter.h
new file mode 100644
index 0000000..88b445e
--- /dev/null
+++ b/src/extratransmitters/rtpfaketransmitter.h
@@ -0,0 +1,241 @@
+/*
+
+ This class allows for jrtp to process packets without sending them out
+ anywhere.
+ The incoming messages are handed in to jrtp through the TransmissionParams
+ and can be retreived from jrtp through the normal polling mecanisms.
+ The outgoing RTP/RTCP packets are given to jrtp through the normal
+ session->SendPacket() and those packets are handed back out to the
+ client through a callback function (packet_ready_cb).
+
+ example usage : Allows for integration of RTP into gstreamer.
+
+ Copyright (c) 2005 Philippe Khalaf <burger@speedy.org>
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2004 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.luc.ac.be), a research center of the "Limburgs Universitair
+ Centrum" (http://www.luc.ac.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#ifndef RTPFAKETRANSMITTER_H
+
+#define RTPFAKETRANSMITTER_H
+
+#include "rtpconfig.h"
+
+#include "rtptransmitter.h"
+#include "rtpipv4destination.h"
+#include "rtphashtable.h"
+#include "rtpkeyhashtable.h"
+#include <list>
+
+#ifdef RTP_SUPPORT_THREAD
+ #include <jmutex.h>
+#endif // RTP_SUPPORT_THREAD
+
+#define RTPFAKETRANS_HASHSIZE 8317
+#define RTPFAKETRANS_DEFAULTPORTBASE 5000
+
+// Definition of a callback that is called when a packet is ready for sending
+// params (*data, data_len, dest_addr, dest_port, rtp [1 if rtp, 0 if rtcp])
+typedef void(*packet_ready_cb)(void*, uint8_t*, uint16_t, uint32_t, uint16_t, int rtp);
+
+class RTPFakeTransmissionParams : public RTPTransmissionParams
+{
+public:
+ RTPFakeTransmissionParams():RTPTransmissionParams(RTPTransmitter::UserDefinedProto) { portbase = RTPFAKETRANS_DEFAULTPORTBASE; bindIP = 0; multicastTTL = 1; currentdata = NULL;}
+ void SetBindIP(uint32_t ip) { bindIP = ip; }
+ void SetPortbase(uint16_t pbase) { portbase = pbase; }
+ void SetMulticastTTL(uint8_t mcastTTL) { multicastTTL = mcastTTL; }
+ void SetLocalIPList(std::list<uint32_t> &iplist) { localIPs = iplist; }
+ void ClearLocalIPList() { localIPs.clear(); }
+ void SetCurrentData(uint8_t *data) { currentdata = data; }
+ void SetCurrentDataLen(uint16_t len) { currentdatalen = len; }
+ void SetCurrentDataAddr(uint32_t addr) { currentdataaddr = addr; }
+ void SetCurrentDataPort(uint16_t port) { currentdataport = port; }
+ void SetCurrentDataType(bool type) { currentdatatype = type; }
+ void SetPacketReadyCB(packet_ready_cb cb) { packetreadycb = cb; };
+ void SetPacketReadyCBData(void *data) { packetreadycbdata = data; };
+ uint32_t GetBindIP() const { return bindIP; }
+ uint16_t GetPortbase() const { return portbase; }
+ uint8_t GetMulticastTTL() const { return multicastTTL; }
+ const std::list<uint32_t> &GetLocalIPList() const { return localIPs; }
+ uint8_t* GetCurrentData() const { return currentdata; }
+ uint16_t GetCurrentDataLen() const { return currentdatalen; }
+ uint32_t GetCurrentDataAddr() const { return currentdataaddr; }
+ uint16_t GetCurrentDataPort() const { return currentdataport; }
+ bool GetCurrentDataType() const { return currentdatatype; }
+ packet_ready_cb GetPacketReadyCB() const { return packetreadycb; }
+ void* GetPacketReadyCBData() const { return packetreadycbdata; }
+private:
+ uint16_t portbase;
+ uint32_t bindIP;
+ std::list<uint32_t> localIPs;
+ uint8_t multicastTTL;
+ uint8_t* currentdata;
+ uint16_t currentdatalen;
+ uint32_t currentdataaddr;
+ uint16_t currentdataport;
+ bool currentdatatype;
+ packet_ready_cb packetreadycb;
+ void *packetreadycbdata;
+};
+
+class RTPFakeTransmissionInfo : public RTPTransmissionInfo
+{
+public:
+ RTPFakeTransmissionInfo(std::list<uint32_t> iplist,
+ RTPFakeTransmissionParams *transparams) :
+ RTPTransmissionInfo(RTPTransmitter::UserDefinedProto)
+ { localIPlist = iplist; params = transparams; }
+
+ ~RTPFakeTransmissionInfo() { }
+ std::list<uint32_t> GetLocalIPList() const { return localIPlist; }
+ RTPFakeTransmissionParams* GetTransParams() { return params; }
+private:
+ std::list<uint32_t> localIPlist;
+ RTPFakeTransmissionParams *params;
+};
+
+class RTPFakeTrans_GetHashIndex_IPv4Dest
+{
+public:
+ static int GetIndex(const RTPIPv4Destination &d) { return d.GetIP()%RTPFAKETRANS_HASHSIZE; }
+};
+
+class RTPFakeTrans_GetHashIndex_uint32_t
+{
+public:
+ static int GetIndex(const uint32_t &k) { return k%RTPFAKETRANS_HASHSIZE; }
+};
+
+#define RTPFAKETRANS_HEADERSIZE (20+8)
+
+class RTPFakeTransmitter : public RTPTransmitter
+{
+public:
+ RTPFakeTransmitter(RTPMemoryManager *mgr);
+ ~RTPFakeTransmitter();
+
+ int Init(bool treadsafe);
+ int Create(size_t maxpacksize,const RTPTransmissionParams *transparams);
+ void Destroy();
+ RTPTransmissionInfo *GetTransmissionInfo();
+
+ int GetLocalHostName(uint8_t *buffer,size_t *bufferlength);
+ bool ComesFromThisTransmitter(const RTPAddress *addr);
+ size_t GetHeaderOverhead() { return RTPFAKETRANS_HEADERSIZE; }
+
+ int Poll();
+ int WaitForIncomingData(const RTPTime &delay,bool *dataavailable = 0);
+ int AbortWait();
+
+ int SendRTPData(const void *data,size_t len);
+ int SendRTCPData(const void *data,size_t len);
+
+ int AddDestination(const RTPAddress &addr);
+ int DeleteDestination(const RTPAddress &addr);
+ void ClearDestinations();
+
+ bool SupportsMulticasting();
+ int JoinMulticastGroup(const RTPAddress &addr);
+ int LeaveMulticastGroup(const RTPAddress &addr);
+ void LeaveAllMulticastGroups();
+
+ int SetReceiveMode(RTPTransmitter::ReceiveMode m);
+ int AddToIgnoreList(const RTPAddress &addr);
+ int DeleteFromIgnoreList(const RTPAddress &addr);
+ void ClearIgnoreList();
+ int AddToAcceptList(const RTPAddress &addr);
+ int DeleteFromAcceptList(const RTPAddress &addr);
+ void ClearAcceptList();
+ int SetMaximumPacketSize(size_t s);
+
+ bool NewDataAvailable();
+ RTPRawPacket *GetNextPacket();
+#ifdef RTPDEBUG
+ void Dump();
+#endif // RTPDEBUG
+private:
+ int CreateLocalIPList();
+ bool GetLocalIPList_Interfaces();
+ void GetLocalIPList_DNS();
+ void AddLoopbackAddress();
+ void FlushPackets();
+ int FakePoll();
+ int ProcessAddAcceptIgnoreEntry(uint32_t ip,uint16_t port);
+ int ProcessDeleteAcceptIgnoreEntry(uint32_t ip,uint16_t port);
+#ifdef RTP_SUPPORT_IPV4MULTICAST
+ bool SetMulticastTTL(uint8_t ttl);
+#endif // RTP_SUPPORT_IPV4MULTICAST
+ bool ShouldAcceptData(uint32_t srcip,uint16_t srcport);
+ void ClearAcceptIgnoreInfo();
+
+ RTPFakeTransmissionParams *params;
+ bool init;
+ bool created;
+ bool waitingfordata;
+ std::list<uint32_t> localIPs;
+ uint16_t portbase;
+ uint8_t multicastTTL;
+ RTPTransmitter::ReceiveMode receivemode;
+
+ uint8_t *localhostname;
+ size_t localhostnamelength;
+
+ RTPHashTable<const RTPIPv4Destination,RTPFakeTrans_GetHashIndex_IPv4Dest,RTPFAKETRANS_HASHSIZE> destinations;
+#ifdef RTP_SUPPORT_IPV4MULTICAST
+// RTPHashTable<const uint32_t,RTPFakeTrans_GetHashIndex_uint32_t,RTPFAKETRANS_HASHSIZE> multicastgroups;
+#endif // RTP_SUPPORT_IPV4MULTICAST
+ std::list<RTPRawPacket*> rawpacketlist;
+
+ bool supportsmulticasting;
+ size_t maxpacksize;
+
+ class PortInfo
+ {
+ public:
+ PortInfo() { all = false; }
+
+ bool all;
+ std::list<uint16_t> portlist;
+ };
+
+ RTPKeyHashTable<const uint32_t,PortInfo*,RTPFakeTrans_GetHashIndex_uint32_t,RTPFAKETRANS_HASHSIZE> acceptignoreinfo;
+
+ int CreateAbortDescriptors();
+ void DestroyAbortDescriptors();
+ void AbortWaitInternal();
+#ifdef RTP_SUPPORT_THREAD
+ JMutex mainmutex,waitmutex;
+ int threadsafe;
+#endif // RTP_SUPPORT_THREAD
+};
+
+#endif // RTPFakeTRANSMITTER_H
+
diff --git a/src/rtcpapppacket.cpp b/src/rtcpapppacket.cpp
new file mode 100644
index 0000000..d7a3904
--- /dev/null
+++ b/src/rtcpapppacket.cpp
@@ -0,0 +1,87 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtcpapppacket.h"
+#ifdef RTPDEBUG
+ #include <iostream>
+ #include <string>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+RTCPAPPPacket::RTCPAPPPacket(uint8_t *data,size_t datalength)
+ : RTCPPacket(APP,data,datalength)
+{
+ knownformat = false;
+
+ RTCPCommonHeader *hdr;
+ size_t len = datalength;
+
+ hdr = (RTCPCommonHeader *)data;
+ if (hdr->padding)
+ {
+ uint8_t padcount = data[datalength-1];
+ if ((padcount & 0x03) != 0) // not a multiple of four! (see rfc 3550 p 37)
+ return;
+ if (((size_t)padcount) >= len)
+ return;
+ len -= (size_t)padcount;
+ }
+
+ if (len < (sizeof(RTCPCommonHeader)+sizeof(uint32_t)*2))
+ return;
+ len -= (sizeof(RTCPCommonHeader)+sizeof(uint32_t)*2);
+ appdatalen = len;
+ knownformat = true;
+}
+
+#ifdef RTPDEBUG
+void RTCPAPPPacket::Dump()
+{
+ RTCPPacket::Dump();
+ if (!IsKnownFormat())
+ {
+ std::cout << " Unknown format!" << std::endl;
+ }
+ else
+ {
+ std::cout << " SSRC: " << GetSSRC() << std::endl;
+
+ char str[5];
+ memcpy(str,GetName(),4);
+ str[4] = 0;
+ std::cout << " Name: " << std::string(str).c_str() << std::endl;
+ std::cout << " Length: " << GetAPPDataLength() << std::endl;
+ }
+}
+#endif // RTPDEBUG
+
diff --git a/src/rtcpapppacket.h b/src/rtcpapppacket.h
new file mode 100644
index 0000000..4e5f9b7
--- /dev/null
+++ b/src/rtcpapppacket.h
@@ -0,0 +1,127 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtcpapppacket.h
+ */
+
+#ifndef RTCPAPPPACKET_H
+
+#define RTCPAPPPACKET_H
+
+#include "rtpconfig.h"
+#include "rtcppacket.h"
+#include "rtpstructs.h"
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ #include <netinet/in.h>
+#endif // WIN32
+
+class RTCPCompoundPacket;
+
+/** Describes an RTCP APP packet. */
+class RTCPAPPPacket : public RTCPPacket
+{
+public:
+ /** Creates an instance based on the data in \c data with length \c datalen.
+ * Creates an instance based on the data in \c data with length \c datalen. Since the \c data pointer
+ * is referenced inside the class (no copy of the data is made) one must make sure that the memory it
+ * points to is valid as long as the class instance exists.
+ */
+ RTCPAPPPacket(uint8_t *data,size_t datalen);
+ ~RTCPAPPPacket() { }
+
+ /** Returns the subtype contained in the APP packet. */
+ uint8_t GetSubType() const;
+
+ /** Returns the SSRC of the source which sent this packet. */
+ uint32_t GetSSRC() const;
+
+ /** Returns the name contained in the APP packet.
+ * Returns the name contained in the APP packet. This alway consists of four bytes and is not NULL-terminated.
+ */
+ uint8_t *GetName();
+
+ /** Returns a pointer to the actual data. */
+ uint8_t *GetAPPData();
+
+ /** Returns the length of the actual data. */
+ size_t GetAPPDataLength() const;
+#ifdef RTPDEBUG
+ void Dump();
+#endif // RTPDEBUG
+private:
+ size_t appdatalen;
+};
+
+inline uint8_t RTCPAPPPacket::GetSubType() const
+{
+ if (!knownformat)
+ return 0;
+ RTCPCommonHeader *hdr = (RTCPCommonHeader *)data;
+ return hdr->count;
+}
+
+inline uint32_t RTCPAPPPacket::GetSSRC() const
+{
+ if (!knownformat)
+ return 0;
+
+ uint32_t *ssrc = (uint32_t *)(data+sizeof(RTCPCommonHeader));
+ return ntohl(*ssrc);
+}
+
+inline uint8_t *RTCPAPPPacket::GetName()
+{
+ if (!knownformat)
+ return 0;
+
+ return (data+sizeof(RTCPCommonHeader)+sizeof(uint32_t));
+}
+
+inline uint8_t *RTCPAPPPacket::GetAPPData()
+{
+ if (!knownformat)
+ return 0;
+ if (appdatalen == 0)
+ return 0;
+ return (data+sizeof(RTCPCommonHeader)+sizeof(uint32_t)*2);
+}
+
+inline size_t RTCPAPPPacket::GetAPPDataLength() const
+{
+ if (!knownformat)
+ return 0;
+ return appdatalen;
+}
+
+#endif // RTCPAPPPACKET_H
+
diff --git a/src/rtcpbyepacket.cpp b/src/rtcpbyepacket.cpp
new file mode 100644
index 0000000..794a3b8
--- /dev/null
+++ b/src/rtcpbyepacket.cpp
@@ -0,0 +1,98 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtcpbyepacket.h"
+#ifdef RTPDEBUG
+ #include <iostream>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+RTCPBYEPacket::RTCPBYEPacket(uint8_t *data,size_t datalength)
+ : RTCPPacket(BYE,data,datalength)
+{
+ knownformat = false;
+ reasonoffset = 0;
+
+ RTCPCommonHeader *hdr;
+ size_t len = datalength;
+
+ hdr = (RTCPCommonHeader *)data;
+ if (hdr->padding)
+ {
+ uint8_t padcount = data[datalength-1];
+ if ((padcount & 0x03) != 0) // not a multiple of four! (see rfc 3550 p 37)
+ return;
+ if (((size_t)padcount) >= len)
+ return;
+ len -= (size_t)padcount;
+ }
+
+ size_t ssrclen = ((size_t)(hdr->count))*sizeof(uint32_t) + sizeof(RTCPCommonHeader);
+ if (ssrclen > len)
+ return;
+ if (ssrclen < len) // there's probably a reason for leaving
+ {
+ uint8_t *reasonlength = (data+ssrclen);
+ size_t reaslen = (size_t)(*reasonlength);
+ if (reaslen > (len-ssrclen-1))
+ return;
+ reasonoffset = ssrclen;
+ }
+ knownformat = true;
+}
+
+#ifdef RTPDEBUG
+void RTCPBYEPacket::Dump()
+{
+ RTCPPacket::Dump();
+ if (!IsKnownFormat())
+ {
+ std::cout << " Unknown format" << std::endl;
+ return;
+ }
+
+ int num = GetSSRCCount();
+ int i;
+
+ for (i = 0 ; i < num ; i++)
+ std::cout << " SSRC: " << GetSSRC(i) << std::endl;
+ if (HasReasonForLeaving())
+ {
+ char str[1024];
+ memcpy(str,GetReasonData(),GetReasonLength());
+ str[GetReasonLength()] = 0;
+ std::cout << " Reason: " << str << std::endl;
+ }
+}
+#endif // RTPDEBUG
+
diff --git a/src/rtcpbyepacket.h b/src/rtcpbyepacket.h
new file mode 100644
index 0000000..027b856
--- /dev/null
+++ b/src/rtcpbyepacket.h
@@ -0,0 +1,135 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtcpbyepacket.h
+ */
+
+#ifndef RTCPBYEPACKET_H
+
+#define RTCPBYEPACKET_H
+
+#include "rtpconfig.h"
+#include "rtcppacket.h"
+#include "rtpstructs.h"
+#if ! (defined(WIN32) || defined (_WIN32_WCE))
+ #include <netinet/in.h>
+#endif // WIN32
+
+class RTCPCompoundPacket;
+
+/** Describes an RTCP BYE packet. */
+class RTCPBYEPacket : public RTCPPacket
+{
+public:
+ /** Creates an instance based on the data in \c data with length \c datalen.
+ * Creates an instance based on the data in \c data with length \c datalen. Since the \c data pointer
+ * is referenced inside the class (no copy of the data is made) one must make sure that the memory it
+ * points to is valid as long as the class instance exists.
+ */
+ RTCPBYEPacket(uint8_t *data,size_t datalen);
+ ~RTCPBYEPacket() { }
+
+ /** Returns the number of SSRC identifiers present in this BYE packet. */
+ int GetSSRCCount() const;
+
+ /** Returns the SSRC described by \c index which may have a value from 0 to GetSSRCCount()-1
+ * (note that no check is performed to see if \c index is valid).
+ */
+ uint32_t GetSSRC(int index) const; // note: no check is performed to see if index is valid!
+
+ /** Returns true if the BYE packet contains a reason for leaving. */
+ bool HasReasonForLeaving() const;
+
+ /** Returns the length of the string which describes why the source(s) left. */
+ size_t GetReasonLength() const;
+
+ /** Returns the actual reason for leaving data. */
+ uint8_t *GetReasonData();
+
+#ifdef RTPDEBUG
+ void Dump();
+#endif // RTPDEBUG
+private:
+ size_t reasonoffset;
+};
+
+inline int RTCPBYEPacket::GetSSRCCount() const
+{
+ if (!knownformat)
+ return 0;
+
+ RTCPCommonHeader *hdr = (RTCPCommonHeader *)data;
+ return (int)(hdr->count);
+}
+
+inline uint32_t RTCPBYEPacket::GetSSRC(int index) const
+{
+ if (!knownformat)
+ return 0;
+ uint32_t *ssrc = (uint32_t *)(data+sizeof(RTCPCommonHeader)+sizeof(uint32_t)*index);
+ return ntohl(*ssrc);
+}
+
+inline bool RTCPBYEPacket::HasReasonForLeaving() const
+{
+ if (!knownformat)
+ return false;
+ if (reasonoffset == 0)
+ return false;
+ return true;
+}
+
+inline size_t RTCPBYEPacket::GetReasonLength() const
+{
+ if (!knownformat)
+ return 0;
+ if (reasonoffset == 0)
+ return 0;
+ uint8_t *reasonlen = (data+reasonoffset);
+ return (size_t)(*reasonlen);
+}
+
+inline uint8_t *RTCPBYEPacket::GetReasonData()
+{
+ if (!knownformat)
+ return 0;
+ if (reasonoffset == 0)
+ return 0;
+ uint8_t *reasonlen = (data+reasonoffset);
+ if ((*reasonlen) == 0)
+ return 0;
+ return (data+reasonoffset+1);
+}
+
+#endif // RTCPBYEPACKET_H
+
diff --git a/src/rtcpcompoundpacket.cpp b/src/rtcpcompoundpacket.cpp
new file mode 100644
index 0000000..c284fa4
--- /dev/null
+++ b/src/rtcpcompoundpacket.cpp
@@ -0,0 +1,225 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtcpcompoundpacket.h"
+#include "rtprawpacket.h"
+#include "rtperrors.h"
+#include "rtpstructs.h"
+#include "rtpdefines.h"
+#include "rtcpsrpacket.h"
+#include "rtcprrpacket.h"
+#include "rtcpsdespacket.h"
+#include "rtcpbyepacket.h"
+#include "rtcpapppacket.h"
+#include "rtcpunknownpacket.h"
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ #include <netinet/in.h>
+#endif // WIN32
+
+#include "rtpdebug.h"
+
+RTCPCompoundPacket::RTCPCompoundPacket(RTPRawPacket &rawpack, RTPMemoryManager *mgr) : RTPMemoryObject(mgr)
+{
+ compoundpacket = 0;
+ compoundpacketlength = 0;
+ error = 0;
+
+ if (rawpack.IsRTP())
+ {
+ error = ERR_RTP_RTCPCOMPOUND_INVALIDPACKET;
+ return;
+ }
+
+ uint8_t *data = rawpack.GetData();
+ size_t datalen = rawpack.GetDataLength();
+
+ error = ParseData(data,datalen);
+ if (error < 0)
+ return;
+
+ compoundpacket = rawpack.GetData();
+ compoundpacketlength = rawpack.GetDataLength();
+ deletepacket = true;
+
+ rawpack.ZeroData();
+
+ rtcppackit = rtcppacklist.begin();
+}
+
+RTCPCompoundPacket::RTCPCompoundPacket(uint8_t *packet, size_t packetlen, bool deletedata, RTPMemoryManager *mgr) : RTPMemoryObject(mgr)
+{
+ compoundpacket = 0;
+ compoundpacketlength = 0;
+
+ error = ParseData(packet,packetlen);
+ if (error < 0)
+ return;
+
+ compoundpacket = packet;
+ compoundpacketlength = packetlen;
+ deletepacket = deletedata;
+
+ rtcppackit = rtcppacklist.begin();
+}
+
+RTCPCompoundPacket::RTCPCompoundPacket(RTPMemoryManager *mgr) : RTPMemoryObject(mgr)
+{
+ compoundpacket = 0;
+ compoundpacketlength = 0;
+ error = 0;
+ deletepacket = true;
+}
+
+int RTCPCompoundPacket::ParseData(uint8_t *data, size_t datalen)
+{
+ bool first;
+
+ if (datalen < sizeof(RTCPCommonHeader))
+ return ERR_RTP_RTCPCOMPOUND_INVALIDPACKET;
+
+ first = true;
+
+ do
+ {
+ RTCPCommonHeader *rtcphdr;
+ size_t length;
+
+ rtcphdr = (RTCPCommonHeader *)data;
+ if (rtcphdr->version != RTP_VERSION) // check version
+ {
+ ClearPacketList();
+ return ERR_RTP_RTCPCOMPOUND_INVALIDPACKET;
+ }
+ if (first)
+ {
+ // Check if first packet is SR or RR
+
+ first = false;
+ if ( ! (rtcphdr->packettype == RTP_RTCPTYPE_SR || rtcphdr->packettype == RTP_RTCPTYPE_RR))
+ {
+ ClearPacketList();
+ return ERR_RTP_RTCPCOMPOUND_INVALIDPACKET;
+ }
+ }
+
+ length = (size_t)ntohs(rtcphdr->length);
+ length++;
+ length *= sizeof(uint32_t);
+
+ if (length > datalen) // invalid length field
+ {
+ ClearPacketList();
+ return ERR_RTP_RTCPCOMPOUND_INVALIDPACKET;
+ }
+
+ if (rtcphdr->padding)
+ {
+ // check if it's the last packet
+ if (length != datalen)
+ {
+ ClearPacketList();
+ return ERR_RTP_RTCPCOMPOUND_INVALIDPACKET;
+ }
+ }
+
+ RTCPPacket *p;
+
+ switch (rtcphdr->packettype)
+ {
+ case RTP_RTCPTYPE_SR:
+ p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPSRPACKET) RTCPSRPacket(data,length);
+ break;
+ case RTP_RTCPTYPE_RR:
+ p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPRRPACKET) RTCPRRPacket(data,length);
+ break;
+ case RTP_RTCPTYPE_SDES:
+ p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPSDESPACKET) RTCPSDESPacket(data,length);
+ break;
+ case RTP_RTCPTYPE_BYE:
+ p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPBYEPACKET) RTCPBYEPacket(data,length);
+ break;
+ case RTP_RTCPTYPE_APP:
+ p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPAPPPACKET) RTCPAPPPacket(data,length);
+ break;
+ default:
+ p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPUNKNOWNPACKET) RTCPUnknownPacket(data,length);
+ }
+
+ if (p == 0)
+ {
+ ClearPacketList();
+ return ERR_RTP_OUTOFMEM;
+ }
+
+ rtcppacklist.push_back(p);
+
+ datalen -= length;
+ data += length;
+ } while (datalen >= (size_t)sizeof(RTCPCommonHeader));
+
+ if (datalen != 0) // some remaining bytes
+ {
+ ClearPacketList();
+ return ERR_RTP_RTCPCOMPOUND_INVALIDPACKET;
+ }
+ return 0;
+}
+
+RTCPCompoundPacket::~RTCPCompoundPacket()
+{
+ ClearPacketList();
+ if (compoundpacket && deletepacket)
+ RTPDeleteByteArray(compoundpacket,GetMemoryManager());
+}
+
+void RTCPCompoundPacket::ClearPacketList()
+{
+ std::list<RTCPPacket *>::const_iterator it;
+
+ for (it = rtcppacklist.begin() ; it != rtcppacklist.end() ; it++)
+ RTPDelete(*it,GetMemoryManager());
+ rtcppacklist.clear();
+ rtcppackit = rtcppacklist.begin();
+}
+
+#ifdef RTPDEBUG
+void RTCPCompoundPacket::Dump()
+{
+ std::list<RTCPPacket *>::const_iterator it;
+ for (it = rtcppacklist.begin() ; it != rtcppacklist.end() ; it++)
+ {
+ RTCPPacket *p = *it;
+
+ p->Dump();
+ }
+}
+#endif // RTPDEBUG
diff --git a/src/rtcpcompoundpacket.h b/src/rtcpcompoundpacket.h
new file mode 100644
index 0000000..0b7fa66
--- /dev/null
+++ b/src/rtcpcompoundpacket.h
@@ -0,0 +1,106 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtcpcompoundpacket.h
+ */
+
+#ifndef RTCPCOMPOUNDPACKET_H
+
+#define RTCPCOMPOUNDPACKET_H
+
+#include "rtpconfig.h"
+#include "rtptypes.h"
+#include "rtpmemoryobject.h"
+#include <list>
+
+class RTPRawPacket;
+class RTCPPacket;
+
+/** Represents an RTCP compound packet. */
+class RTCPCompoundPacket : public RTPMemoryObject
+{
+public:
+ /** Creates an RTCPCompoundPacket instance from the data in \c rawpack, installing a memory manager if specified. */
+ RTCPCompoundPacket(RTPRawPacket &rawpack, RTPMemoryManager *memmgr = 0);
+
+ /** Creates an RTCPCompoundPacket instance from the data in \c packet}, with size \c len.
+ * Creates an RTCPCompoundPacket instance from the data in \c packet}, with size \c len. The \c deletedata
+ * flag specifies if the data in \c packet should be deleted when the compound packet is destroyed. If
+ * specified, a memory manager will be installed.
+ */
+ RTCPCompoundPacket(uint8_t *packet, size_t len, bool deletedata = true, RTPMemoryManager *memmgr = 0);
+protected:
+ RTCPCompoundPacket(RTPMemoryManager *memmgr); // this is for the compoundpacket builder
+public:
+ virtual ~RTCPCompoundPacket();
+
+ /** Checks if the RTCP compound packet was created successfully.
+ * If the raw packet data in the constructor could not be parsed, this function returns the error code of
+ * what went wrong. If the packet had an invalid format, the return value is \c ERR_RTP_RTCPCOMPOUND_INVALIDPACKET.
+ */
+ int GetCreationError() { return error; }
+
+ /** Returns a pointer to the data of the entire RTCP compound packet. */
+ uint8_t *GetCompoundPacketData() { return compoundpacket; }
+
+ /** Returns the size of the entire RTCP compound packet. */
+ size_t GetCompoundPacketLength() { return compoundpacketlength; }
+
+ /** Starts the iteration over the individual RTCP packets in the RTCP compound packet. */
+ void GotoFirstPacket() { rtcppackit = rtcppacklist.begin(); }
+
+ /** Returns a pointer to the next individual RTCP packet.
+ * Returns a pointer to the next individual RTCP packet. Note that no \c delete call may be done
+ * on the RTCPPacket instance which is returned.
+ */
+ RTCPPacket *GetNextPacket() { if (rtcppackit == rtcppacklist.end()) return 0; RTCPPacket *p = *rtcppackit; rtcppackit++; return p; }
+
+#ifdef RTPDEBUG
+ void Dump();
+#endif // RTPDEBUG
+protected:
+ void ClearPacketList();
+ int ParseData(uint8_t *packet, size_t len);
+
+ int error;
+
+ uint8_t *compoundpacket;
+ size_t compoundpacketlength;
+ bool deletepacket;
+
+ std::list<RTCPPacket *> rtcppacklist;
+ std::list<RTCPPacket *>::const_iterator rtcppackit;
+};
+
+#endif // RTCPCOMPOUNDPACKET_H
+
diff --git a/src/rtcpcompoundpacketbuilder.cpp b/src/rtcpcompoundpacketbuilder.cpp
new file mode 100644
index 0000000..8172007
--- /dev/null
+++ b/src/rtcpcompoundpacketbuilder.cpp
@@ -0,0 +1,675 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtcpcompoundpacketbuilder.h"
+#include "rtcpsrpacket.h"
+#include "rtcprrpacket.h"
+#include "rtcpsdespacket.h"
+#include "rtcpbyepacket.h"
+#include "rtcpapppacket.h"
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ #include <netinet/in.h>
+#endif // WIN32
+
+#include "rtpdebug.h"
+
+RTCPCompoundPacketBuilder::RTCPCompoundPacketBuilder(RTPMemoryManager *mgr) : RTCPCompoundPacket(mgr), report(mgr), sdes(mgr)
+{
+ byesize = 0;
+ appsize = 0;
+ maximumpacketsize = 0;
+ buffer = 0;
+ external = false;
+ arebuilding = false;
+}
+
+RTCPCompoundPacketBuilder::~RTCPCompoundPacketBuilder()
+{
+ if (external)
+ compoundpacket = 0; // make sure RTCPCompoundPacket doesn't delete the external buffer
+ ClearBuildBuffers();
+}
+
+void RTCPCompoundPacketBuilder::ClearBuildBuffers()
+{
+ report.Clear();
+ sdes.Clear();
+
+ std::list<Buffer>::const_iterator it;
+ for (it = byepackets.begin() ; it != byepackets.end() ; it++)
+ {
+ if ((*it).packetdata)
+ RTPDeleteByteArray((*it).packetdata,GetMemoryManager());
+ }
+ for (it = apppackets.begin() ; it != apppackets.end() ; it++)
+ {
+ if ((*it).packetdata)
+ RTPDeleteByteArray((*it).packetdata,GetMemoryManager());
+ }
+
+ byepackets.clear();
+ apppackets.clear();
+ byesize = 0;
+ appsize = 0;
+}
+
+int RTCPCompoundPacketBuilder::InitBuild(size_t maxpacketsize)
+{
+ if (arebuilding)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYBUILDING;
+ if (compoundpacket)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYBUILT;
+
+ if (maxpacketsize < RTP_MINPACKETSIZE)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_MAXPACKETSIZETOOSMALL;
+
+ maximumpacketsize = maxpacketsize;
+ buffer = 0;
+ external = false;
+ byesize = 0;
+ appsize = 0;
+
+ arebuilding = true;
+ return 0;
+}
+
+int RTCPCompoundPacketBuilder::InitBuild(void *externalbuffer,size_t buffersize)
+{
+ if (arebuilding)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYBUILDING;
+ if (compoundpacket)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYBUILT;
+
+ if (buffersize < RTP_MINPACKETSIZE)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_BUFFERSIZETOOSMALL;
+
+ maximumpacketsize = buffersize;
+ buffer = (uint8_t *)externalbuffer;
+ external = true;
+ byesize = 0;
+ appsize = 0;
+
+ arebuilding = true;
+ return 0;
+}
+
+int RTCPCompoundPacketBuilder::StartSenderReport(uint32_t senderssrc,const RTPNTPTime &ntptimestamp,uint32_t rtptimestamp,
+ uint32_t packetcount,uint32_t octetcount)
+{
+ if (!arebuilding)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
+
+ if (report.headerlength != 0)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYGOTREPORT;
+
+ size_t totalsize = byesize+appsize+sdes.NeededBytes();
+ size_t sizeleft = maximumpacketsize-totalsize;
+ size_t neededsize = sizeof(RTCPCommonHeader)+sizeof(uint32_t)+sizeof(RTCPSenderReport);
+
+ if (neededsize > sizeleft)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
+
+ // fill in some things
+
+ report.headerlength = sizeof(uint32_t)+sizeof(RTCPSenderReport);
+ report.isSR = true;
+
+ uint32_t *ssrc = (uint32_t *)report.headerdata;
+ *ssrc = htonl(senderssrc);
+
+ RTCPSenderReport *sr = (RTCPSenderReport *)(report.headerdata + sizeof(uint32_t));
+ sr->ntptime_msw = htonl(ntptimestamp.GetMSW());
+ sr->ntptime_lsw = htonl(ntptimestamp.GetLSW());
+ sr->rtptimestamp = htonl(rtptimestamp);
+ sr->packetcount = htonl(packetcount);
+ sr->octetcount = htonl(octetcount);
+
+ return 0;
+}
+
+int RTCPCompoundPacketBuilder::StartReceiverReport(uint32_t senderssrc)
+{
+ if (!arebuilding)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
+ if (report.headerlength != 0)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYGOTREPORT;
+
+ size_t totalsize = byesize+appsize+sdes.NeededBytes();
+ size_t sizeleft = maximumpacketsize-totalsize;
+ size_t neededsize = sizeof(RTCPCommonHeader)+sizeof(uint32_t);
+
+ if (neededsize > sizeleft)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
+
+ // fill in some things
+
+ report.headerlength = sizeof(uint32_t);
+ report.isSR = false;
+
+ uint32_t *ssrc = (uint32_t *)report.headerdata;
+ *ssrc = htonl(senderssrc);
+
+ return 0;
+}
+
+int RTCPCompoundPacketBuilder::AddReportBlock(uint32_t ssrc,uint8_t fractionlost,int32_t packetslost,uint32_t exthighestseq,
+ uint32_t jitter,uint32_t lsr,uint32_t dlsr)
+{
+ if (!arebuilding)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
+ if (report.headerlength == 0)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_REPORTNOTSTARTED;
+
+ size_t totalothersize = byesize+appsize+sdes.NeededBytes();
+ size_t reportsizewithextrablock = report.NeededBytesWithExtraReportBlock();
+
+ if ((totalothersize+reportsizewithextrablock) > maximumpacketsize)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
+
+ uint8_t *buf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPRECEIVERREPORT) uint8_t[sizeof(RTCPReceiverReport)];
+ if (buf == 0)
+ return ERR_RTP_OUTOFMEM;
+
+ RTCPReceiverReport *rr = (RTCPReceiverReport *)buf;
+ uint32_t *packlost = (uint32_t *)&packetslost;
+ uint32_t packlost2 = (*packlost);
+
+ rr->ssrc = htonl(ssrc);
+ rr->fractionlost = fractionlost;
+ rr->packetslost[2] = (uint8_t)(packlost2&0xFF);
+ rr->packetslost[1] = (uint8_t)((packlost2>>8)&0xFF);
+ rr->packetslost[0] = (uint8_t)((packlost2>>16)&0xFF);
+ rr->exthighseqnr = htonl(exthighestseq);
+ rr->jitter = htonl(jitter);
+ rr->lsr = htonl(lsr);
+ rr->dlsr = htonl(dlsr);
+
+ report.reportblocks.push_back(Buffer(buf,sizeof(RTCPReceiverReport)));
+ return 0;
+}
+
+int RTCPCompoundPacketBuilder::AddSDESSource(uint32_t ssrc)
+{
+ if (!arebuilding)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
+
+ size_t totalotherbytes = byesize+appsize+report.NeededBytes();
+ size_t sdessizewithextrasource = sdes.NeededBytesWithExtraSource();
+
+ if ((totalotherbytes + sdessizewithextrasource) > maximumpacketsize)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
+
+ int status;
+
+ if ((status = sdes.AddSSRC(ssrc)) < 0)
+ return status;
+ return 0;
+}
+
+int RTCPCompoundPacketBuilder::AddSDESNormalItem(RTCPSDESPacket::ItemType t,const void *itemdata,uint8_t itemlength)
+{
+ if (!arebuilding)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
+ if (sdes.sdessources.empty())
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOCURRENTSOURCE;
+
+ uint8_t itemid;
+
+ switch(t)
+ {
+ case RTCPSDESPacket::CNAME:
+ itemid = RTCP_SDES_ID_CNAME;
+ break;
+ case RTCPSDESPacket::NAME:
+ itemid = RTCP_SDES_ID_NAME;
+ break;
+ case RTCPSDESPacket::EMAIL:
+ itemid = RTCP_SDES_ID_EMAIL;
+ break;
+ case RTCPSDESPacket::PHONE:
+ itemid = RTCP_SDES_ID_PHONE;
+ break;
+ case RTCPSDESPacket::LOC:
+ itemid = RTCP_SDES_ID_LOCATION;
+ break;
+ case RTCPSDESPacket::TOOL:
+ itemid = RTCP_SDES_ID_TOOL;
+ break;
+ case RTCPSDESPacket::NOTE:
+ itemid = RTCP_SDES_ID_NOTE;
+ break;
+ default:
+ return ERR_RTP_RTCPCOMPPACKBUILDER_INVALIDITEMTYPE;
+ }
+
+ size_t totalotherbytes = byesize+appsize+report.NeededBytes();
+ size_t sdessizewithextraitem = sdes.NeededBytesWithExtraItem(itemlength);
+
+ if ((sdessizewithextraitem+totalotherbytes) > maximumpacketsize)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
+
+ uint8_t *buf;
+ size_t len;
+
+ buf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_BUFFER_RTCPSDESBLOCK) uint8_t[sizeof(RTCPSDESHeader)+(size_t)itemlength];
+ if (buf == 0)
+ return ERR_RTP_OUTOFMEM;
+ len = sizeof(RTCPSDESHeader)+(size_t)itemlength;
+
+ RTCPSDESHeader *sdeshdr = (RTCPSDESHeader *)(buf);
+
+ sdeshdr->sdesid = itemid;
+ sdeshdr->length = itemlength;
+ if (itemlength != 0)
+ memcpy((buf + sizeof(RTCPSDESHeader)),itemdata,(size_t)itemlength);
+
+ sdes.AddItem(buf,len);
+ return 0;
+}
+
+#ifdef RTP_SUPPORT_SDESPRIV
+int RTCPCompoundPacketBuilder::AddSDESPrivateItem(const void *prefixdata,uint8_t prefixlength,const void *valuedata,
+ uint8_t valuelength)
+{
+ if (!arebuilding)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
+ if (sdes.sdessources.empty())
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOCURRENTSOURCE;
+
+ size_t itemlength = ((size_t)prefixlength)+1+((size_t)valuelength);
+ if (itemlength > 255)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_TOTALITEMLENGTHTOOBIG;
+
+ size_t totalotherbytes = byesize+appsize+report.NeededBytes();
+ size_t sdessizewithextraitem = sdes.NeededBytesWithExtraItem(itemlength);
+
+ if ((sdessizewithextraitem+totalotherbytes) > maximumpacketsize)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
+
+ uint8_t *buf;
+ size_t len;
+
+ buf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_BUFFER_RTCPSDESBLOCK) uint8_t[sizeof(RTCPSDESHeader)+itemlength];
+ if (buf == 0)
+ return ERR_RTP_OUTOFMEM;
+ len = sizeof(RTCPSDESHeader)+(size_t)itemlength;
+
+ RTCPSDESHeader *sdeshdr = (RTCPSDESHeader *)(buf);
+
+ sdeshdr->sdesid = RTCP_SDES_ID_PRIVATE;
+ sdeshdr->length = itemlength;
+
+ buf[sizeof(RTCPSDESHeader)] = prefixlength;
+ if (prefixlength != 0)
+ memcpy((buf+sizeof(RTCPSDESHeader)+1),prefixdata,(size_t)prefixlength);
+ if (valuelength != 0)
+ memcpy((buf+sizeof(RTCPSDESHeader)+1+(size_t)prefixlength),valuedata,(size_t)valuelength);
+
+ sdes.AddItem(buf,len);
+ return 0;
+}
+#endif // RTP_SUPPORT_SDESPRIV
+
+int RTCPCompoundPacketBuilder::AddBYEPacket(uint32_t *ssrcs,uint8_t numssrcs,const void *reasondata,uint8_t reasonlength)
+{
+ if (!arebuilding)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
+
+ if (numssrcs > 31)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_TOOMANYSSRCS;
+
+ size_t packsize = sizeof(RTCPCommonHeader)+sizeof(uint32_t)*((size_t)numssrcs);
+ size_t zerobytes = 0;
+
+ if (reasonlength > 0)
+ {
+ packsize += 1; // 1 byte for the length;
+ packsize += (size_t)reasonlength;
+
+ size_t r = (packsize&0x03);
+ if (r != 0)
+ {
+ zerobytes = 4-r;
+ packsize += zerobytes;
+ }
+ }
+
+ size_t totalotherbytes = appsize+byesize+sdes.NeededBytes()+report.NeededBytes();
+
+ if ((totalotherbytes + packsize) > maximumpacketsize)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
+
+ uint8_t *buf;
+ size_t numwords;
+
+ buf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_BUFFER_RTCPBYEPACKET) uint8_t[packsize];
+ if (buf == 0)
+ return ERR_RTP_OUTOFMEM;
+
+ RTCPCommonHeader *hdr = (RTCPCommonHeader *)buf;
+
+ hdr->version = 2;
+ hdr->padding = 0;
+ hdr->count = numssrcs;
+
+ numwords = packsize/sizeof(uint32_t);
+ hdr->length = htons((uint16_t)(numwords-1));
+ hdr->packettype = RTP_RTCPTYPE_BYE;
+
+ uint32_t *sources = (uint32_t *)(buf+sizeof(RTCPCommonHeader));
+ uint8_t srcindex;
+
+ for (srcindex = 0 ; srcindex < numssrcs ; srcindex++)
+ sources[srcindex] = htonl(ssrcs[srcindex]);
+
+ if (reasonlength != 0)
+ {
+ size_t offset = sizeof(RTCPCommonHeader)+((size_t)numssrcs)*sizeof(uint32_t);
+
+ buf[offset] = reasonlength;
+ memcpy((buf+offset+1),reasondata,(size_t)reasonlength);
+ for (size_t i = 0 ; i < zerobytes ; i++)
+ buf[packsize-1-i] = 0;
+ }
+
+ byepackets.push_back(Buffer(buf,packsize));
+ byesize += packsize;
+
+ return 0;
+}
+
+int RTCPCompoundPacketBuilder::AddAPPPacket(uint8_t subtype,uint32_t ssrc,const uint8_t name[4],const void *appdata,size_t appdatalen)
+{
+ if (!arebuilding)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
+ if (subtype > 31)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_ILLEGALSUBTYPE;
+ if ((appdatalen%4) != 0)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_ILLEGALAPPDATALENGTH;
+
+ size_t appdatawords = appdatalen/4;
+
+ if ((appdatawords+2) > 65535)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_APPDATALENTOOBIG;
+
+ size_t packsize = sizeof(RTCPCommonHeader)+sizeof(uint32_t)*2+appdatalen;
+ size_t totalotherbytes = appsize+byesize+sdes.NeededBytes()+report.NeededBytes();
+
+ if ((totalotherbytes + packsize) > maximumpacketsize)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
+
+ uint8_t *buf;
+
+ buf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_BUFFER_RTCPAPPPACKET) uint8_t[packsize];
+ if (buf == 0)
+ return ERR_RTP_OUTOFMEM;
+
+ RTCPCommonHeader *hdr = (RTCPCommonHeader *)buf;
+
+ hdr->version = 2;
+ hdr->padding = 0;
+ hdr->count = subtype;
+
+ hdr->length = htons((uint16_t)(appdatawords+2));
+ hdr->packettype = RTP_RTCPTYPE_APP;
+
+ uint32_t *source = (uint32_t *)(buf+sizeof(RTCPCommonHeader));
+ *source = htonl(ssrc);
+
+ buf[sizeof(RTCPCommonHeader)+sizeof(uint32_t)+0] = name[0];
+ buf[sizeof(RTCPCommonHeader)+sizeof(uint32_t)+1] = name[1];
+ buf[sizeof(RTCPCommonHeader)+sizeof(uint32_t)+2] = name[2];
+ buf[sizeof(RTCPCommonHeader)+sizeof(uint32_t)+3] = name[3];
+
+ if (appdatalen > 0)
+ memcpy((buf+sizeof(RTCPCommonHeader)+sizeof(uint32_t)*2),appdata,appdatalen);
+
+ apppackets.push_back(Buffer(buf,packsize));
+ appsize += packsize;
+
+ return 0;
+}
+
+int RTCPCompoundPacketBuilder::EndBuild()
+{
+ if (!arebuilding)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
+ if (report.headerlength == 0)
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOREPORTPRESENT;
+
+ uint8_t *buf;
+ size_t len;
+
+ len = appsize+byesize+report.NeededBytes()+sdes.NeededBytes();
+
+ if (!external)
+ {
+ buf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_BUFFER_RTCPCOMPOUNDPACKET) uint8_t[len];
+ if (buf == 0)
+ return ERR_RTP_OUTOFMEM;
+ }
+ else
+ buf = buffer;
+
+ uint8_t *curbuf = buf;
+ RTCPPacket *p;
+
+ // first, we'll add all report info
+
+ {
+ bool firstpacket = true;
+ bool done = false;
+ std::list<Buffer>::const_iterator it = report.reportblocks.begin();
+ do
+ {
+ RTCPCommonHeader *hdr = (RTCPCommonHeader *)curbuf;
+ size_t offset;
+
+ hdr->version = 2;
+ hdr->padding = 0;
+
+ if (firstpacket && report.isSR)
+ {
+ hdr->packettype = RTP_RTCPTYPE_SR;
+ memcpy((curbuf+sizeof(RTCPCommonHeader)),report.headerdata,report.headerlength);
+ offset = sizeof(RTCPCommonHeader)+report.headerlength;
+ }
+ else
+ {
+ hdr->packettype = RTP_RTCPTYPE_RR;
+ memcpy((curbuf+sizeof(RTCPCommonHeader)),report.headerdata,sizeof(uint32_t));
+ offset = sizeof(RTCPCommonHeader)+sizeof(uint32_t);
+ }
+ firstpacket = false;
+
+ uint8_t count = 0;
+
+ while (it != report.reportblocks.end() && count < 31)
+ {
+ memcpy(curbuf+offset,(*it).packetdata,(*it).packetlength);
+ offset += (*it).packetlength;
+ count++;
+ it++;
+ }
+
+ size_t numwords = offset/sizeof(uint32_t);
+
+ hdr->length = htons((uint16_t)(numwords-1));
+ hdr->count = count;
+
+ // add entry in parent's list
+ if (hdr->packettype == RTP_RTCPTYPE_SR)
+ p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPSRPACKET) RTCPSRPacket(curbuf,offset);
+ else
+ p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPRRPACKET) RTCPRRPacket(curbuf,offset);
+ if (p == 0)
+ {
+ if (!external)
+ RTPDeleteByteArray(buf,GetMemoryManager());
+ ClearPacketList();
+ return ERR_RTP_OUTOFMEM;
+ }
+ rtcppacklist.push_back(p);
+
+ curbuf += offset;
+ if (it == report.reportblocks.end())
+ done = true;
+ } while (!done);
+ }
+
+ // then, we'll add the sdes info
+
+ if (!sdes.sdessources.empty())
+ {
+ bool done = false;
+ std::list<SDESSource *>::const_iterator sourceit = sdes.sdessources.begin();
+
+ do
+ {
+ RTCPCommonHeader *hdr = (RTCPCommonHeader *)curbuf;
+ size_t offset = sizeof(RTCPCommonHeader);
+
+ hdr->version = 2;
+ hdr->padding = 0;
+ hdr->packettype = RTP_RTCPTYPE_SDES;
+
+ uint8_t sourcecount = 0;
+
+ while (sourceit != sdes.sdessources.end() && sourcecount < 31)
+ {
+ uint32_t *ssrc = (uint32_t *)(curbuf+offset);
+ *ssrc = htonl((*sourceit)->ssrc);
+ offset += sizeof(uint32_t);
+
+ std::list<Buffer>::const_iterator itemit,itemend;
+
+ itemit = (*sourceit)->items.begin();
+ itemend = (*sourceit)->items.end();
+ while (itemit != itemend)
+ {
+ memcpy(curbuf+offset,(*itemit).packetdata,(*itemit).packetlength);
+ offset += (*itemit).packetlength;
+ itemit++;
+ }
+
+ curbuf[offset] = 0; // end of item list;
+ offset++;
+
+ size_t r = offset&0x03;
+ if (r != 0) // align to 32 bit boundary
+ {
+ size_t num = 4-r;
+ size_t i;
+
+ for (i = 0 ; i < num ; i++)
+ curbuf[offset+i] = 0;
+ offset += num;
+ }
+
+ sourceit++;
+ sourcecount++;
+ }
+
+ size_t numwords = offset/4;
+
+ hdr->count = sourcecount;
+ hdr->length = htons((uint16_t)(numwords-1));
+
+ p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPSDESPACKET) RTCPSDESPacket(curbuf,offset);
+ if (p == 0)
+ {
+ if (!external)
+ RTPDeleteByteArray(buf,GetMemoryManager());
+ ClearPacketList();
+ return ERR_RTP_OUTOFMEM;
+ }
+ rtcppacklist.push_back(p);
+
+ curbuf += offset;
+ if (sourceit == sdes.sdessources.end())
+ done = true;
+ } while (!done);
+ }
+
+ // adding the app data
+
+ {
+ std::list<Buffer>::const_iterator it;
+
+ for (it = apppackets.begin() ; it != apppackets.end() ; it++)
+ {
+ memcpy(curbuf,(*it).packetdata,(*it).packetlength);
+
+ p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPAPPPACKET) RTCPAPPPacket(curbuf,(*it).packetlength);
+ if (p == 0)
+ {
+ if (!external)
+ RTPDeleteByteArray(buf,GetMemoryManager());
+ ClearPacketList();
+ return ERR_RTP_OUTOFMEM;
+ }
+ rtcppacklist.push_back(p);
+
+ curbuf += (*it).packetlength;
+ }
+ }
+
+ // adding bye packets
+
+ {
+ std::list<Buffer>::const_iterator it;
+
+ for (it = byepackets.begin() ; it != byepackets.end() ; it++)
+ {
+ memcpy(curbuf,(*it).packetdata,(*it).packetlength);
+
+ p = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPBYEPACKET) RTCPBYEPacket(curbuf,(*it).packetlength);
+ if (p == 0)
+ {
+ if (!external)
+ RTPDeleteByteArray(buf,GetMemoryManager());
+ ClearPacketList();
+ return ERR_RTP_OUTOFMEM;
+ }
+ rtcppacklist.push_back(p);
+
+ curbuf += (*it).packetlength;
+ }
+ }
+
+ compoundpacket = buf;
+ compoundpacketlength = len;
+ arebuilding = false;
+ ClearBuildBuffers();
+ return 0;
+}
+
diff --git a/src/rtcpcompoundpacketbuilder.h b/src/rtcpcompoundpacketbuilder.h
new file mode 100644
index 0000000..4537105
--- /dev/null
+++ b/src/rtcpcompoundpacketbuilder.h
@@ -0,0 +1,383 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtcpcompoundpacketbuilder.h
+ */
+
+#ifndef RTCPCOMPOUNDPACKETBUILDER_H
+
+#define RTCPCOMPOUNDPACKETBUILDER_H
+
+#include "rtpconfig.h"
+#include "rtcpcompoundpacket.h"
+#include "rtptimeutilities.h"
+#include "rtcpsdespacket.h"
+#include "rtperrors.h"
+#include <list>
+
+class RTPMemoryManager;
+
+/** This class can be used to construct an RTCP compound packet.
+ * The RTCPCompoundPacketBuilder class can be used to construct an RTCP compound packet. It inherits the member
+ * functions of RTCPCompoundPacket which can be used to access the information in the compound packet once it has
+ * been built successfully. The member functions described below return \c ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT
+ * if the action would cause the maximum allowed size to be exceeded.
+ */
+class RTCPCompoundPacketBuilder : public RTCPCompoundPacket
+{
+public:
+ /** Constructs an RTCPCompoundPacketBuilder instance, optionally installing a memory manager. */
+ RTCPCompoundPacketBuilder(RTPMemoryManager *memmgr = 0);
+ ~RTCPCompoundPacketBuilder();
+
+ /** Starts building an RTCP compound packet with maximum size \c maxpacketsize.
+ * Starts building an RTCP compound packet with maximum size \c maxpacketsize. New memory will be allocated
+ * to store the packet.
+ */
+ int InitBuild(size_t maxpacketsize);
+
+ /** Starts building a RTCP compound packet.
+ * Starts building a RTCP compound packet. Data will be stored in \c externalbuffer which
+ * can contain \c buffersize bytes.
+ */
+ int InitBuild(void *externalbuffer,size_t buffersize);
+
+ /** Adds a sender report to the compound packet.
+ * Tells the packet builder that the packet should start with a sender report which will contain
+ * the sender information specified by this function's arguments. Once the sender report is started,
+ * report blocks can be added using the AddReportBlock function.
+ */
+ int StartSenderReport(uint32_t senderssrc,const RTPNTPTime &ntptimestamp,uint32_t rtptimestamp,
+ uint32_t packetcount,uint32_t octetcount);
+
+ /** Adds a receiver report to the compound packet.
+ * Tells the packet builder that the packet should start with a receiver report which will contain
+ * he sender SSRC \c senderssrc. Once the sender report is started, report blocks can be added using the
+ * AddReportBlock function.
+ */
+ int StartReceiverReport(uint32_t senderssrc);
+
+ /** Adds the report block information specified by the function's arguments.
+ * Adds the report block information specified by the function's arguments. If more than 31 report blocks
+ * are added, the builder will automatically use a new RTCP receiver report packet.
+ */
+ int AddReportBlock(uint32_t ssrc,uint8_t fractionlost,int32_t packetslost,uint32_t exthighestseq,
+ uint32_t jitter,uint32_t lsr,uint32_t dlsr);
+
+ /** Starts an SDES chunk for participant \c ssrc. */
+ int AddSDESSource(uint32_t ssrc);
+
+ /** Adds a normal (non-private) SDES item of type \c t to the current SDES chunk.
+ * Adds a normal (non-private) SDES item of type \c t to the current SDES chunk. The item's value
+ * will have length \c itemlength and will contain the data \c itemdata.
+ */
+ int AddSDESNormalItem(RTCPSDESPacket::ItemType t,const void *itemdata,uint8_t itemlength);
+#ifdef RTP_SUPPORT_SDESPRIV
+ /** Adds an SDES PRIV item described by the function's arguments to the current SDES chunk. */
+ int AddSDESPrivateItem(const void *prefixdata,uint8_t prefixlength,const void *valuedata,
+ uint8_t valuelength);
+#endif // RTP_SUPPORT_SDESPRIV
+
+ /** Adds a BYE packet to the compound packet.
+ * Adds a BYE packet to the compound packet. It will contain \c numssrcs source identifiers specified in
+ * \c ssrcs and will indicate as reason for leaving the string of length \c reasonlength
+ * containing data \c reasondata.
+ */
+ int AddBYEPacket(uint32_t *ssrcs,uint8_t numssrcs,const void *reasondata,uint8_t reasonlength);
+
+ /** Adds the APP packet specified by the arguments to the compound packet.
+ * Adds the APP packet specified by the arguments to the compound packet. Note that \c appdatalen has to be
+ * a multiple of four.
+ */
+ int AddAPPPacket(uint8_t subtype,uint32_t ssrc,const uint8_t name[4],const void *appdata,size_t appdatalen);
+
+ /** Finishes building the compound packet.
+ * Finishes building the compound packet. If successful, the RTCPCompoundPacket member functions
+ * can be used to access the RTCP packet data.
+ */
+ int EndBuild();
+private:
+ class Buffer
+ {
+ public:
+ Buffer():packetdata(0),packetlength(0) { }
+ Buffer(uint8_t *data,size_t len):packetdata(data),packetlength(len) { }
+
+ uint8_t *packetdata;
+ size_t packetlength;
+ };
+
+ class Report : public RTPMemoryObject
+ {
+ public:
+ Report(RTPMemoryManager *mgr) : RTPMemoryObject(mgr)
+ {
+ headerdata = (uint8_t *)headerdata32;
+ isSR = false;
+ headerlength = 0;
+ }
+ ~Report() { Clear(); }
+
+ void Clear()
+ {
+ std::list<Buffer>::const_iterator it;
+ for (it = reportblocks.begin() ; it != reportblocks.end() ; it++)
+ {
+ if ((*it).packetdata)
+ RTPDeleteByteArray((*it).packetdata,GetMemoryManager());
+ }
+ reportblocks.clear();
+ isSR = false;
+ headerlength = 0;
+ }
+
+ size_t NeededBytes()
+ {
+ size_t x,n,d,r;
+ n = reportblocks.size();
+ if (n == 0)
+ {
+ if (headerlength == 0)
+ return 0;
+ x = sizeof(RTCPCommonHeader)+headerlength;
+ }
+ else
+ {
+ x = n*sizeof(RTCPReceiverReport);
+ d = n/31; // max 31 reportblocks per report
+ r = n%31;
+ if (r != 0)
+ d++;
+ x += d*(sizeof(RTCPCommonHeader)+sizeof(uint32_t)); /* header and SSRC */
+ if (isSR)
+ x += sizeof(RTCPSenderReport);
+ }
+ return x;
+ }
+
+ size_t NeededBytesWithExtraReportBlock()
+ {
+ size_t x,n,d,r;
+ n = reportblocks.size() + 1; // +1 for the extra block
+ x = n*sizeof(RTCPReceiverReport);
+ d = n/31; // max 31 reportblocks per report
+ r = n%31;
+ if (r != 0)
+ d++;
+ x += d*(sizeof(RTCPCommonHeader)+sizeof(uint32_t)); /* header and SSRC */
+ if (isSR)
+ x += sizeof(RTCPSenderReport);
+ return x;
+ }
+
+ bool isSR;
+
+ uint8_t *headerdata;
+ uint32_t headerdata32[(sizeof(uint32_t)+sizeof(RTCPSenderReport))/sizeof(uint32_t)]; // either for ssrc and sender info or just ssrc
+ size_t headerlength;
+ std::list<Buffer> reportblocks;
+ };
+
+ class SDESSource : public RTPMemoryObject
+ {
+ public:
+ SDESSource(uint32_t s,RTPMemoryManager *mgr) : RTPMemoryObject(mgr),ssrc(s),totalitemsize(0) { }
+ ~SDESSource()
+ {
+ std::list<Buffer>::const_iterator it;
+ for (it = items.begin() ; it != items.end() ; it++)
+ {
+ if ((*it).packetdata)
+ RTPDeleteByteArray((*it).packetdata,GetMemoryManager());
+ }
+ items.clear();
+ }
+
+ size_t NeededBytes()
+ {
+ size_t x,r;
+ x = totalitemsize + 1; // +1 for the 0 byte which terminates the item list
+ r = x%sizeof(uint32_t);
+ if (r != 0)
+ x += (sizeof(uint32_t)-r); // make sure it ends on a 32 bit boundary
+ x += sizeof(uint32_t); // for ssrc
+ return x;
+ }
+
+ size_t NeededBytesWithExtraItem(uint8_t itemdatalength)
+ {
+ size_t x,r;
+ x = totalitemsize + sizeof(RTCPSDESHeader) + (size_t)itemdatalength + 1;
+ r = x%sizeof(uint32_t);
+ if (r != 0)
+ x += (sizeof(uint32_t)-r); // make sure it ends on a 32 bit boundary
+ x += sizeof(uint32_t); // for ssrc
+ return x;
+ }
+
+ void AddItem(uint8_t *buf,size_t len)
+ {
+ Buffer b(buf,len);
+ totalitemsize += len;
+ items.push_back(b);
+ }
+
+ uint32_t ssrc;
+ std::list<Buffer> items;
+ private:
+ size_t totalitemsize;
+ };
+
+ class SDES : public RTPMemoryObject
+ {
+ public:
+ SDES(RTPMemoryManager *mgr) : RTPMemoryObject(mgr) { sdesit = sdessources.end(); }
+ ~SDES() { Clear(); }
+
+ void Clear()
+ {
+ std::list<SDESSource *>::const_iterator it;
+
+ for (it = sdessources.begin() ; it != sdessources.end() ; it++)
+ RTPDelete(*it,GetMemoryManager());
+ sdessources.clear();
+ }
+
+ int AddSSRC(uint32_t ssrc)
+ {
+ SDESSource *s = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_SDESSOURCE) SDESSource(ssrc,GetMemoryManager());
+ if (s == 0)
+ return ERR_RTP_OUTOFMEM;
+ sdessources.push_back(s);
+ sdesit = sdessources.end();
+ sdesit--;
+ return 0;
+ }
+
+ int AddItem(uint8_t *buf,size_t len)
+ {
+ if (sdessources.empty())
+ return ERR_RTP_RTCPCOMPPACKBUILDER_NOCURRENTSOURCE;
+ (*sdesit)->AddItem(buf,len);
+ return 0;
+ }
+
+ size_t NeededBytes()
+ {
+ std::list<SDESSource *>::const_iterator it;
+ size_t x = 0;
+ size_t n,d,r;
+
+ if (sdessources.empty())
+ return 0;
+
+ for (it = sdessources.begin() ; it != sdessources.end() ; it++)
+ x += (*it)->NeededBytes();
+ n = sdessources.size();
+ d = n/31;
+ r = n%31;
+ if (r != 0)
+ d++;
+ x += d*sizeof(RTCPCommonHeader);
+ return x;
+ }
+
+ size_t NeededBytesWithExtraItem(uint8_t itemdatalength)
+ {
+ std::list<SDESSource *>::const_iterator it;
+ size_t x = 0;
+ size_t n,d,r;
+
+ if (sdessources.empty())
+ return 0;
+
+ for (it = sdessources.begin() ; it != sdesit ; it++)
+ x += (*it)->NeededBytes();
+ x += (*sdesit)->NeededBytesWithExtraItem(itemdatalength);
+ n = sdessources.size();
+ d = n/31;
+ r = n%31;
+ if (r != 0)
+ d++;
+ x += d*sizeof(RTCPCommonHeader);
+ return x;
+ }
+
+ size_t NeededBytesWithExtraSource()
+ {
+ std::list<SDESSource *>::const_iterator it;
+ size_t x = 0;
+ size_t n,d,r;
+
+ if (sdessources.empty())
+ return 0;
+
+ for (it = sdessources.begin() ; it != sdessources.end() ; it++)
+ x += (*it)->NeededBytes();
+
+ // for the extra source we'll need at least 8 bytes (ssrc and four 0 bytes)
+ x += sizeof(uint32_t)*2;
+
+ n = sdessources.size() + 1; // also, the number of sources will increase
+ d = n/31;
+ r = n%31;
+ if (r != 0)
+ d++;
+ x += d*sizeof(RTCPCommonHeader);
+ return x;
+ }
+
+ std::list<SDESSource *> sdessources;
+ private:
+ std::list<SDESSource *>::const_iterator sdesit;
+ };
+
+ size_t maximumpacketsize;
+ uint8_t *buffer;
+ bool external;
+ bool arebuilding;
+
+ Report report;
+ SDES sdes;
+
+ std::list<Buffer> byepackets;
+ size_t byesize;
+
+ std::list<Buffer> apppackets;
+ size_t appsize;
+
+ void ClearBuildBuffers();
+};
+
+#endif // RTCPCOMPOUNDPACKETBUILDER_H
+
diff --git a/src/rtcppacket.cpp b/src/rtcppacket.cpp
new file mode 100644
index 0000000..76f55ba
--- /dev/null
+++ b/src/rtcppacket.cpp
@@ -0,0 +1,71 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtcppacket.h"
+#ifdef RTPDEBUG
+ #include <iostream>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+#ifdef RTPDEBUG
+
+void RTCPPacket::Dump()
+{
+ switch(packettype)
+ {
+ case SR:
+ std::cout << "RTCP Sender Report ";
+ break;
+ case RR:
+ std::cout << "RTCP Receiver Report ";
+ break;
+ case SDES:
+ std::cout << "RTCP Source Description ";
+ break;
+ case APP:
+ std::cout << "RTCP APP Packet ";
+ break;
+ case BYE:
+ std::cout << "RTCP Bye Packet ";
+ break;
+ case Unknown:
+ std::cout << "Unknown RTCP Packet ";
+ break;
+ default:
+ std::cout << "ERROR: Invalid packet type!" << std::endl;
+ }
+ std::cout << "Length: " << datalen;
+ std::cout << std::endl;
+}
+
+#endif // RTPDEBUG
diff --git a/src/rtcppacket.h b/src/rtcppacket.h
new file mode 100644
index 0000000..1062574
--- /dev/null
+++ b/src/rtcppacket.h
@@ -0,0 +1,89 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtcppacket.h
+ */
+
+#ifndef RTCPPACKET_H
+
+#define RTCPPACKET_H
+
+#include "rtpconfig.h"
+#include "rtptypes.h"
+
+class RTCPCompoundPacket;
+
+/** Base class for specific types of RTCP packets. */
+class RTCPPacket
+{
+public:
+ /** Identifies the specific kind of RTCP packet. */
+ enum PacketType
+ {
+ SR, /**< An RTCP sender report. */
+ RR, /**< An RTCP receiver report. */
+ SDES, /**< An RTCP source description packet. */
+ BYE, /**< An RTCP bye packet. */
+ APP, /**< An RTCP packet containing application specific data. */
+ Unknown /**< The type of RTCP packet was not recognized. */
+ };
+protected:
+ RTCPPacket(PacketType t,uint8_t *d,size_t dlen) : data(d),datalen(dlen),packettype(t) { knownformat = false; }
+public:
+ virtual ~RTCPPacket() { }
+
+ /** Returns \c true if the subclass was able to interpret the data and \c false otherwise. */
+ bool IsKnownFormat() const { return knownformat; }
+
+ /** Returns the actual packet type which the subclass implements. */
+ PacketType GetPacketType() const { return packettype; }
+
+ /** Returns a pointer to the data of this RTCP packet. */
+ uint8_t *GetPacketData() { return data; }
+
+ /** Returns the length of this RTCP packet. */
+ size_t GetPacketLength() const { return datalen; }
+
+#ifdef RTPDEBUG
+ virtual void Dump();
+#endif // RTPDEBUG
+protected:
+ uint8_t *data;
+ size_t datalen;
+ bool knownformat;
+private:
+ const PacketType packettype;
+};
+
+#endif // RTCPPACKET_H
+
diff --git a/src/rtcppacketbuilder.cpp b/src/rtcppacketbuilder.cpp
new file mode 100644
index 0000000..7e07d8f
--- /dev/null
+++ b/src/rtcppacketbuilder.cpp
@@ -0,0 +1,736 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtcppacketbuilder.h"
+#include "rtpsources.h"
+#include "rtppacketbuilder.h"
+#include "rtcpscheduler.h"
+#include "rtpsourcedata.h"
+#include "rtcpcompoundpacketbuilder.h"
+#include "rtpmemorymanager.h"
+
+#include "rtpdebug.h"
+
+RTCPPacketBuilder::RTCPPacketBuilder(RTPSources &s,RTPPacketBuilder &pb,RTPMemoryManager *mgr)
+ : RTPMemoryObject(mgr),sources(s),rtppacketbuilder(pb),prevbuildtime(0,0),transmissiondelay(0,0),ownsdesinfo(mgr)
+{
+ init = false;
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ timeinit.Dummy();
+#endif // WIN32 || _WIN32_WCE
+}
+
+RTCPPacketBuilder::~RTCPPacketBuilder()
+{
+ Destroy();
+}
+
+int RTCPPacketBuilder::Init(size_t maxpacksize,double tsunit,const void *cname,size_t cnamelen)
+{
+ if (init)
+ return ERR_RTP_RTCPPACKETBUILDER_ALREADYINIT;
+ if (maxpacksize < RTP_MINPACKETSIZE)
+ return ERR_RTP_RTCPPACKETBUILDER_ILLEGALMAXPACKSIZE;
+ if (tsunit < 0.0)
+ return ERR_RTP_RTCPPACKETBUILDER_ILLEGALTIMESTAMPUNIT;
+
+ if (cnamelen>255)
+ cnamelen = 255;
+
+ maxpacketsize = maxpacksize;
+ timestampunit = tsunit;
+
+ int status;
+
+ if ((status = ownsdesinfo.SetCNAME((const uint8_t *)cname,cnamelen)) < 0)
+ return status;
+
+ ClearAllSourceFlags();
+
+ interval_name = -1;
+ interval_email = -1;
+ interval_location = -1;
+ interval_phone = -1;
+ interval_tool = -1;
+ interval_note = -1;
+
+ sdesbuildcount = 0;
+ transmissiondelay = RTPTime(0,0);
+
+ firstpacket = true;
+ processingsdes = false;
+ init = true;
+ return 0;
+}
+
+void RTCPPacketBuilder::Destroy()
+{
+ if (!init)
+ return;
+ ownsdesinfo.Clear();
+ init = false;
+}
+
+int RTCPPacketBuilder::BuildNextPacket(RTCPCompoundPacket **pack)
+{
+ if (!init)
+ return ERR_RTP_RTCPPACKETBUILDER_NOTINIT;
+
+ RTCPCompoundPacketBuilder *rtcpcomppack;
+ int status;
+ bool sender = false;
+ RTPSourceData *srcdat;
+
+ *pack = 0;
+
+ rtcpcomppack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPCOMPOUNDPACKETBUILDER) RTCPCompoundPacketBuilder(GetMemoryManager());
+ if (rtcpcomppack == 0)
+ return ERR_RTP_OUTOFMEM;
+
+ if ((status = rtcpcomppack->InitBuild(maxpacketsize)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ return status;
+ }
+
+ if ((srcdat = sources.GetOwnSourceInfo()) != 0)
+ {
+ if (srcdat->IsSender())
+ sender = true;
+ }
+
+ uint32_t ssrc = rtppacketbuilder.GetSSRC();
+ RTPTime curtime = RTPTime::CurrentTime();
+
+ if (sender)
+ {
+ RTPTime rtppacktime = rtppacketbuilder.GetPacketTime();
+ uint32_t rtppacktimestamp = rtppacketbuilder.GetPacketTimestamp();
+ uint32_t packcount = rtppacketbuilder.GetPacketCount();
+ uint32_t octetcount = rtppacketbuilder.GetPayloadOctetCount();
+ RTPTime diff = curtime;
+ diff -= rtppacktime;
+ diff += transmissiondelay; // the sample being sampled at this very instant will need a larger timestamp
+
+ uint32_t tsdiff = (uint32_t)((diff.GetDouble()/timestampunit)+0.5);
+ uint32_t rtptimestamp = rtppacktimestamp+tsdiff;
+ RTPNTPTime ntptimestamp = curtime.GetNTPTime();
+
+ if ((status = rtcpcomppack->StartSenderReport(ssrc,ntptimestamp,rtptimestamp,packcount,octetcount)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON;
+ return status;
+ }
+ }
+ else
+ {
+ if ((status = rtcpcomppack->StartReceiverReport(ssrc)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON;
+ return status;
+ }
+ }
+
+ uint8_t *owncname;
+ size_t owncnamelen;
+
+ owncname = ownsdesinfo.GetCNAME(&owncnamelen);
+
+ if ((status = rtcpcomppack->AddSDESSource(ssrc)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON;
+ return status;
+ }
+ if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::CNAME,owncname,owncnamelen)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON;
+ return status;
+ }
+
+ if (!processingsdes)
+ {
+ int added,skipped;
+ bool full,atendoflist;
+
+ if ((status = FillInReportBlocks(rtcpcomppack,curtime,sources.GetTotalCount(),&full,&added,&skipped,&atendoflist)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ return status;
+ }
+
+ if (full && added == 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON;
+ }
+
+ if (!full)
+ {
+ processingsdes = true;
+ sdesbuildcount++;
+
+ ClearAllSourceFlags();
+
+ doname = false;
+ doemail = false;
+ doloc = false;
+ dophone = false;
+ dotool = false;
+ donote = false;
+ if (interval_name > 0 && ((sdesbuildcount%interval_name) == 0)) doname = true;
+ if (interval_email > 0 && ((sdesbuildcount%interval_email) == 0)) doemail = true;
+ if (interval_location > 0 && ((sdesbuildcount%interval_location) == 0)) doloc = true;
+ if (interval_phone > 0 && ((sdesbuildcount%interval_phone) == 0)) dophone = true;
+ if (interval_tool > 0 && ((sdesbuildcount%interval_tool) == 0)) dotool = true;
+ if (interval_note > 0 && ((sdesbuildcount%interval_note) == 0)) donote = true;
+
+ bool processedall;
+ int itemcount;
+
+ if ((status = FillInSDES(rtcpcomppack,&full,&processedall,&itemcount)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ return status;
+ }
+
+ if (processedall)
+ {
+ processingsdes = false;
+ ClearAllSDESFlags();
+ if (!full && skipped > 0)
+ {
+ // if the packet isn't full and we skipped some
+ // sources that we already got in a previous packet,
+ // we can add some of them now
+
+ bool atendoflist;
+
+ if ((status = FillInReportBlocks(rtcpcomppack,curtime,skipped,&full,&added,&skipped,&atendoflist)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ return status;
+ }
+ }
+ }
+ }
+ }
+ else // previous sdes processing wasn't finished
+ {
+ bool processedall;
+ int itemcount;
+ bool full;
+
+ if ((status = FillInSDES(rtcpcomppack,&full,&processedall,&itemcount)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ return status;
+ }
+
+ if (itemcount == 0) // Big problem: packet size is too small to let any progress happen
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON;
+ }
+
+ if (processedall)
+ {
+ processingsdes = false;
+ ClearAllSDESFlags();
+ if (!full)
+ {
+ // if the packet isn't full and we skipped some
+ // we can add some report blocks
+
+ int added,skipped;
+ bool atendoflist;
+
+ if ((status = FillInReportBlocks(rtcpcomppack,curtime,sources.GetTotalCount(),&full,&added,&skipped,&atendoflist)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ return status;
+ }
+ if (atendoflist) // filled in all possible sources
+ ClearAllSourceFlags();
+ }
+ }
+ }
+
+ if ((status = rtcpcomppack->EndBuild()) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ return status;
+ }
+
+ *pack = rtcpcomppack;
+ firstpacket = false;
+ prevbuildtime = curtime;
+ return 0;
+}
+
+void RTCPPacketBuilder::ClearAllSourceFlags()
+{
+ if (sources.GotoFirstSource())
+ {
+ do
+ {
+ RTPSourceData *srcdat = sources.GetCurrentSourceInfo();
+ srcdat->SetProcessedInRTCP(false);
+ } while (sources.GotoNextSource());
+ }
+}
+
+int RTCPPacketBuilder::FillInReportBlocks(RTCPCompoundPacketBuilder *rtcpcomppack,const RTPTime &curtime,int maxcount,bool *full,int *added,int *skipped,bool *atendoflist)
+{
+ RTPSourceData *srcdat;
+ int addedcount = 0;
+ int skippedcount = 0;
+ bool done = false;
+ bool filled = false;
+ bool atend = false;
+ int status;
+
+ if (sources.GotoFirstSource())
+ {
+ do
+ {
+ bool shouldprocess = false;
+
+ srcdat = sources.GetCurrentSourceInfo();
+ if (!srcdat->IsOwnSSRC()) // don't send to ourselves
+ {
+ if (!srcdat->IsCSRC()) // p 35: no reports should go to CSRCs
+ {
+ if (srcdat->INF_HasSentData()) // if this isn't true, INF_GetLastRTPPacketTime() won't make any sense
+ {
+ if (firstpacket)
+ shouldprocess = true;
+ else
+ {
+ // p 35: only if rtp packets were received since the last RTP packet, a report block
+ // should be added
+
+ RTPTime lastrtptime = srcdat->INF_GetLastRTPPacketTime();
+
+ if (lastrtptime > prevbuildtime)
+ shouldprocess = true;
+ }
+ }
+ }
+ }
+
+ if (shouldprocess)
+ {
+ if (srcdat->IsProcessedInRTCP()) // already covered this one
+ {
+ skippedcount++;
+ }
+ else
+ {
+ uint32_t rr_ssrc = srcdat->GetSSRC();
+ uint32_t num = srcdat->INF_GetNumPacketsReceivedInInterval();
+ uint32_t prevseq = srcdat->INF_GetSavedExtendedSequenceNumber();
+ uint32_t curseq = srcdat->INF_GetExtendedHighestSequenceNumber();
+ uint32_t expected = curseq-prevseq;
+ uint8_t fraclost;
+
+ if (expected < num) // got duplicates
+ fraclost = 0;
+ else
+ {
+ double lost = (double)(expected-num);
+ double frac = lost/((double)expected);
+ fraclost = (uint8_t)(frac*256.0);
+ }
+
+ expected = curseq-srcdat->INF_GetBaseSequenceNumber();
+ num = srcdat->INF_GetNumPacketsReceived();
+
+ uint32_t diff = expected-num;
+ int32_t *packlost = (int32_t *)&diff;
+
+ uint32_t jitter = srcdat->INF_GetJitter();
+ uint32_t lsr;
+ uint32_t dlsr;
+
+ if (!srcdat->SR_HasInfo())
+ {
+ lsr = 0;
+ dlsr = 0;
+ }
+ else
+ {
+ RTPNTPTime srtime = srcdat->SR_GetNTPTimestamp();
+ uint32_t m = (srtime.GetMSW()&0xFFFF);
+ uint32_t l = ((srtime.GetLSW()>>16)&0xFFFF);
+ lsr = ((m<<16)|l);
+
+ RTPTime diff = curtime;
+ diff -= srcdat->SR_GetReceiveTime();
+ double diff2 = diff.GetDouble();
+ diff2 *= 65536.0;
+ dlsr = (uint32_t)diff2;
+ }
+
+ status = rtcpcomppack->AddReportBlock(rr_ssrc,fraclost,*packlost,curseq,jitter,lsr,dlsr);
+ if (status < 0)
+ {
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ {
+ done = true;
+ filled = true;
+ }
+ else
+ return status;
+ }
+ else
+ {
+ addedcount++;
+ if (addedcount >= maxcount)
+ {
+ done = true;
+ if (!sources.GotoNextSource())
+ atend = true;
+ }
+ srcdat->INF_StartNewInterval();
+ srcdat->SetProcessedInRTCP(true);
+ }
+ }
+ }
+
+ if (!done)
+ {
+ if (!sources.GotoNextSource())
+ {
+ atend = true;
+ done = true;
+ }
+ }
+
+ } while (!done);
+ }
+
+ *added = addedcount;
+ *skipped = skippedcount;
+ *full = filled;
+
+ if (!atend) // search for available sources
+ {
+ bool shouldprocess = false;
+
+ do
+ {
+ srcdat = sources.GetCurrentSourceInfo();
+ if (!srcdat->IsOwnSSRC()) // don't send to ourselves
+ {
+ if (!srcdat->IsCSRC()) // p 35: no reports should go to CSRCs
+ {
+ if (srcdat->INF_HasSentData()) // if this isn't true, INF_GetLastRTPPacketTime() won't make any sense
+ {
+ if (firstpacket)
+ shouldprocess = true;
+ else
+ {
+ // p 35: only if rtp packets were received since the last RTP packet, a report block
+ // should be added
+
+ RTPTime lastrtptime = srcdat->INF_GetLastRTPPacketTime();
+
+ if (lastrtptime > prevbuildtime)
+ shouldprocess = true;
+ }
+ }
+ }
+ }
+
+ if (shouldprocess)
+ {
+ if (srcdat->IsProcessedInRTCP())
+ shouldprocess = false;
+ }
+
+ if (!shouldprocess)
+ {
+ if (!sources.GotoNextSource())
+ atend = true;
+ }
+
+ } while (!atend && !shouldprocess);
+ }
+
+ *atendoflist = atend;
+ return 0;
+}
+
+int RTCPPacketBuilder::FillInSDES(RTCPCompoundPacketBuilder *rtcpcomppack,bool *full,bool *processedall,int *added)
+{
+ int status;
+ uint8_t *data;
+ size_t datalen;
+
+ *full = false;
+ *processedall = false;
+ *added = 0;
+
+ // We don't need to add a SSRC for our own data, this is still set
+ // from adding the CNAME
+ if (doname)
+ {
+ if (!ownsdesinfo.ProcessedName())
+ {
+ data = ownsdesinfo.GetName(&datalen);
+ if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::NAME,data,datalen)) < 0)
+ {
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ {
+ *full = true;
+ return 0;
+ }
+ }
+ (*added)++;
+ ownsdesinfo.SetProcessedName(true);
+ }
+ }
+ if (doemail)
+ {
+ if (!ownsdesinfo.ProcessedEMail())
+ {
+ data = ownsdesinfo.GetEMail(&datalen);
+ if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::EMAIL,data,datalen)) < 0)
+ {
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ {
+ *full = true;
+ return 0;
+ }
+ }
+ (*added)++;
+ ownsdesinfo.SetProcessedEMail(true);
+ }
+ }
+ if (doloc)
+ {
+ if (!ownsdesinfo.ProcessedLocation())
+ {
+ data = ownsdesinfo.GetLocation(&datalen);
+ if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::LOC,data,datalen)) < 0)
+ {
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ {
+ *full = true;
+ return 0;
+ }
+ }
+ (*added)++;
+ ownsdesinfo.SetProcessedLocation(true);
+ }
+ }
+ if (dophone)
+ {
+ if (!ownsdesinfo.ProcessedPhone())
+ {
+ data = ownsdesinfo.GetPhone(&datalen);
+ if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::PHONE,data,datalen)) < 0)
+ {
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ {
+ *full = true;
+ return 0;
+ }
+ }
+ (*added)++;
+ ownsdesinfo.SetProcessedPhone(true);
+ }
+ }
+ if (dotool)
+ {
+ if (!ownsdesinfo.ProcessedTool())
+ {
+ data = ownsdesinfo.GetTool(&datalen);
+ if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::TOOL,data,datalen)) < 0)
+ {
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ {
+ *full = true;
+ return 0;
+ }
+ }
+ (*added)++;
+ ownsdesinfo.SetProcessedTool(true);
+ }
+ }
+ if (donote)
+ {
+ if (!ownsdesinfo.ProcessedNote())
+ {
+ data = ownsdesinfo.GetNote(&datalen);
+ if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::NOTE,data,datalen)) < 0)
+ {
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ {
+ *full = true;
+ return 0;
+ }
+ }
+ (*added)++;
+ ownsdesinfo.SetProcessedNote(true);
+ }
+ }
+
+ *processedall = true;
+ return 0;
+}
+
+void RTCPPacketBuilder::ClearAllSDESFlags()
+{
+ ownsdesinfo.ClearFlags();
+}
+
+int RTCPPacketBuilder::BuildBYEPacket(RTCPCompoundPacket **pack,const void *reason,size_t reasonlength,bool useSRifpossible)
+{
+ if (!init)
+ return ERR_RTP_RTCPPACKETBUILDER_NOTINIT;
+
+ RTCPCompoundPacketBuilder *rtcpcomppack;
+ int status;
+
+ if (reasonlength > 255)
+ reasonlength = 255;
+
+ *pack = 0;
+
+ rtcpcomppack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPCOMPOUNDPACKETBUILDER) RTCPCompoundPacketBuilder(GetMemoryManager());
+ if (rtcpcomppack == 0)
+ return ERR_RTP_OUTOFMEM;
+
+ if ((status = rtcpcomppack->InitBuild(maxpacketsize)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ return status;
+ }
+
+ uint32_t ssrc = rtppacketbuilder.GetSSRC();
+ bool useSR = false;
+
+ if (useSRifpossible)
+ {
+ RTPSourceData *srcdat;
+
+ if ((srcdat = sources.GetOwnSourceInfo()) != 0)
+ {
+ if (srcdat->IsSender())
+ useSR = true;
+ }
+ }
+
+ if (useSR)
+ {
+ RTPTime curtime = RTPTime::CurrentTime();
+ RTPTime rtppacktime = rtppacketbuilder.GetPacketTime();
+ uint32_t rtppacktimestamp = rtppacketbuilder.GetPacketTimestamp();
+ uint32_t packcount = rtppacketbuilder.GetPacketCount();
+ uint32_t octetcount = rtppacketbuilder.GetPayloadOctetCount();
+ RTPTime diff = curtime;
+ diff -= rtppacktime;
+
+ uint32_t tsdiff = (uint32_t)((diff.GetDouble()/timestampunit)+0.5);
+ uint32_t rtptimestamp = rtppacktimestamp+tsdiff;
+ RTPNTPTime ntptimestamp = curtime.GetNTPTime();
+
+ if ((status = rtcpcomppack->StartSenderReport(ssrc,ntptimestamp,rtptimestamp,packcount,octetcount)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON;
+ return status;
+ }
+ }
+ else
+ {
+ if ((status = rtcpcomppack->StartReceiverReport(ssrc)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON;
+ return status;
+ }
+ }
+
+ uint8_t *owncname;
+ size_t owncnamelen;
+
+ owncname = ownsdesinfo.GetCNAME(&owncnamelen);
+
+ if ((status = rtcpcomppack->AddSDESSource(ssrc)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON;
+ return status;
+ }
+ if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::CNAME,owncname,owncnamelen)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON;
+ return status;
+ }
+
+ uint32_t ssrcs[1];
+
+ ssrcs[0] = ssrc;
+
+ if ((status = rtcpcomppack->AddBYEPacket(ssrcs,1,(const uint8_t *)reason,reasonlength)) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT)
+ return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON;
+ return status;
+ }
+
+ if ((status = rtcpcomppack->EndBuild()) < 0)
+ {
+ RTPDelete(rtcpcomppack,GetMemoryManager());
+ return status;
+ }
+
+ *pack = rtcpcomppack;
+ return 0;
+}
+
diff --git a/src/rtcppacketbuilder.h b/src/rtcppacketbuilder.h
new file mode 100644
index 0000000..cf043f0
--- /dev/null
+++ b/src/rtcppacketbuilder.h
@@ -0,0 +1,224 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtcppacketbuilder.h
+ */
+
+#ifndef RTCPPACKETBUILDER_H
+
+#define RTCPPACKETBUILDER_H
+
+#include "rtpconfig.h"
+#include "rtptypes.h"
+#include "rtperrors.h"
+#include "rtcpsdesinfo.h"
+#include "rtptimeutilities.h"
+#include "rtpmemoryobject.h"
+
+class RTPSources;
+class RTPPacketBuilder;
+class RTCPScheduler;
+class RTCPCompoundPacket;
+class RTCPCompoundPacketBuilder;
+
+/** This class can be used to build RTCP compound packets, on a higher level than the RTCPCompoundPacketBuilder.
+ * The class RTCPPacketBuilder can be used to build RTCP compound packets. This class is more high-level
+ * than the RTCPCompoundPacketBuilder class: it uses the information of an RTPPacketBuilder instance and of
+ * an RTPSources instance to automatically generate the next compound packet which should be sent. It also
+ * provides functions to determine when SDES items other than the CNAME item should be sent.
+ */
+class RTCPPacketBuilder : public RTPMemoryObject
+{
+public:
+ /** Creates an RTCPPacketBuilder instance.
+ * Creates an instance which will use the source table \c sources and the RTP packet builder
+ * \c rtppackbuilder to determine the information for the next RTCP compound packet. Optionally,
+ * the memory manager \c mgr can be installed.
+ */
+ RTCPPacketBuilder(RTPSources &sources,RTPPacketBuilder &rtppackbuilder, RTPMemoryManager *mgr = 0);
+ ~RTCPPacketBuilder();
+
+ /** Initializes the builder.
+ * Initializes the builder to use the maximum allowed packet size \c maxpacksize, timestamp unit
+ * \c timestampunit and the SDES CNAME item specified by \c cname with length \c cnamelen.
+ * The timestamp unit is defined as a time interval divided by the timestamp interval corresponding to
+ * that interval: for 8000 Hz audio this would be 1/8000.
+ */
+ int Init(size_t maxpacksize,double timestampunit,const void *cname,size_t cnamelen);
+
+ /** Cleans up the builder. */
+ void Destroy();
+
+ /** Sets the timestamp unit to be used to \c tsunit.
+ * Sets the timestamp unit to be used to \c tsunit. The timestamp unit is defined as a time interval
+ * divided by the timestamp interval corresponding to that interval: for 8000 Hz audio this would
+ * be 1/8000.
+ */
+ int SetTimestampUnit(double tsunit) { if (!init) return ERR_RTP_RTCPPACKETBUILDER_NOTINIT; if (tsunit < 0) return ERR_RTP_RTCPPACKETBUILDER_ILLEGALTIMESTAMPUNIT; timestampunit = tsunit; return 0; }
+
+ /** Sets the maximum size allowed size of an RTCP compound packet to \c maxpacksize. */
+ int SetMaximumPacketSize(size_t maxpacksize) { if (!init) return ERR_RTP_RTCPPACKETBUILDER_NOTINIT; if (maxpacksize < RTP_MINPACKETSIZE) return ERR_RTP_RTCPPACKETBUILDER_ILLEGALMAXPACKSIZE; maxpacketsize = maxpacksize; return 0; }
+
+ /** This function allows you to inform RTCP packet builder about the delay between sampling the first
+ * sample of a packet and sending the packet.
+ * This function allows you to inform RTCP packet builder about the delay between sampling the first
+ * sample of a packet and sending the packet. This delay is taken into account when calculating the
+ * relation between RTP timestamp and wallclock time, used for inter-media synchronization.
+ */
+ int SetPreTransmissionDelay(const RTPTime &delay) { if (!init) return ERR_RTP_RTCPPACKETBUILDER_NOTINIT; transmissiondelay = delay; return 0; }
+
+ /** Builds the next RTCP compound packet which should be sent and stores it in \c pack. */
+ int BuildNextPacket(RTCPCompoundPacket **pack);
+
+ /** Builds a BYE packet with reason for leaving specified by \c reason and length \c reasonlength.
+ * Builds a BYE packet with reason for leaving specified by \c reason and length \c reasonlength. If
+ * \c useSRifpossible is set to \c true, the RTCP compound packet will start with a sender report if
+ * allowed. Otherwise, a receiver report is used.
+ */
+ int BuildBYEPacket(RTCPCompoundPacket **pack,const void *reason,size_t reasonlength,bool useSRifpossible = true);
+
+ /** Sets the RTCP interval for the SDES name item.
+ * After all possible sources in the source table have been processed, the class will check if other
+ * SDES items need to be sent. If \c count is zero or negative, nothing will happen. If \c count
+ * is positive, an SDES name item will be added after the sources in the source table have been
+ * processed \c count times.
+ */
+ void SetNameInterval(int count) { if (!init) return; interval_name = count; }
+
+ /** Sets the RTCP interval for the SDES e-mail item.
+ * After all possible sources in the source table have been processed, the class will check if other
+ * SDES items need to be sent. If \c count is zero or negative, nothing will happen. If \c count
+ * is positive, an SDES e-mail item will be added after the sources in the source table have been
+ * processed \c count times.
+ */
+ void SetEMailInterval(int count) { if (!init) return; interval_email = count; }
+
+ /** Sets the RTCP interval for the SDES location item.
+ * After all possible sources in the source table have been processed, the class will check if other
+ * SDES items need to be sent. If \c count is zero or negative, nothing will happen. If \c count
+ * is positive, an SDES location item will be added after the sources in the source table have been
+ * processed \c count times.
+ */
+ void SetLocationInterval(int count) { if (!init) return; interval_location = count; }
+
+ /** Sets the RTCP interval for the SDES phone item.
+ * After all possible sources in the source table have been processed, the class will check if other
+ * SDES items need to be sent. If \c count is zero or negative, nothing will happen. If \c count
+ * is positive, an SDES phone item will be added after the sources in the source table have been
+ * processed \c count times.
+ */
+ void SetPhoneInterval(int count) { if (!init) return; interval_phone = count; }
+
+ /** Sets the RTCP interval for the SDES tool item.
+ * After all possible sources in the source table have been processed, the class will check if other
+ * SDES items need to be sent. If \c count is zero or negative, nothing will happen. If \c count
+ * is positive, an SDES tool item will be added after the sources in the source table have been
+ * processed \c count times.
+ */
+ void SetToolInterval(int count) { if (!init) return; interval_tool = count; }
+
+ /** Sets the RTCP interval for the SDES note item.
+ * After all possible sources in the source table have been processed, the class will check if other
+ * SDES items need to be sent. If \c count is zero or negative, nothing will happen. If \c count
+ * is positive, an SDES note item will be added after the sources in the source table have been
+ * processed \c count times.
+ */
+ void SetNoteInterval(int count) { if (!init) return; interval_note = count; }
+
+ /** Sets the SDES name item for the local participant to the value \c s with length \c len. */
+ int SetLocalName(const void *s,size_t len) { if (!init) return ERR_RTP_RTCPPACKETBUILDER_NOTINIT; return ownsdesinfo.SetName((const uint8_t *)s,len); }
+
+ /** Sets the SDES e-mail item for the local participant to the value \c s with length \c len. */
+ int SetLocalEMail(const void *s,size_t len) { if (!init) return ERR_RTP_RTCPPACKETBUILDER_NOTINIT; return ownsdesinfo.SetEMail((const uint8_t *)s,len); }
+
+ /** Sets the SDES location item for the local participant to the value \c s with length \c len. */
+ int SetLocalLocation(const void *s,size_t len) { if (!init) return ERR_RTP_RTCPPACKETBUILDER_NOTINIT; return ownsdesinfo.SetLocation((const uint8_t *)s,len); }
+
+ /** Sets the SDES phone item for the local participant to the value \c s with length \c len. */
+ int SetLocalPhone(const void *s,size_t len) { if (!init) return ERR_RTP_RTCPPACKETBUILDER_NOTINIT; return ownsdesinfo.SetPhone((const uint8_t *)s,len); }
+
+ /** Sets the SDES tool item for the local participant to the value \c s with length \c len. */
+ int SetLocalTool(const void *s,size_t len) { if (!init) return ERR_RTP_RTCPPACKETBUILDER_NOTINIT; return ownsdesinfo.SetTool((const uint8_t *)s,len); }
+
+ /** Sets the SDES note item for the local participant to the value \c s with length \c len. */
+ int SetLocalNote(const void *s,size_t len) { if (!init) return ERR_RTP_RTCPPACKETBUILDER_NOTINIT; return ownsdesinfo.SetNote((const uint8_t *)s,len); }
+
+ /** Returns the own CNAME item with length \c len */
+ uint8_t *GetLocalCNAME(size_t *len) const { if (!init) return 0; return ownsdesinfo.GetCNAME(len); }
+private:
+ void ClearAllSourceFlags();
+ int FillInReportBlocks(RTCPCompoundPacketBuilder *pack,const RTPTime &curtime,int maxcount,bool *full,int *added,int *skipped,bool *atendoflist);
+ int FillInSDES(RTCPCompoundPacketBuilder *pack,bool *full,bool *processedall,int *added);
+ void ClearAllSDESFlags();
+
+ RTPSources &sources;
+ RTPPacketBuilder &rtppacketbuilder;
+
+ bool init;
+ size_t maxpacketsize;
+ double timestampunit;
+ bool firstpacket;
+ RTPTime prevbuildtime,transmissiondelay;
+
+ class RTCPSDESInfoInternal : public RTCPSDESInfo
+ {
+ public:
+ RTCPSDESInfoInternal(RTPMemoryManager *mgr) : RTCPSDESInfo(mgr) { ClearFlags(); }
+ void ClearFlags() { pname = false; pemail = false; plocation = false; pphone = false; ptool = false; pnote = false; }
+ bool ProcessedName() const { return pname; }
+ bool ProcessedEMail() const { return pemail; }
+ bool ProcessedLocation() const { return plocation; }
+ bool ProcessedPhone() const { return pphone; }
+ bool ProcessedTool() const { return ptool; }
+ bool ProcessedNote() const { return pnote; }
+ void SetProcessedName(bool v) { pname = v; }
+ void SetProcessedEMail(bool v) { pemail = v; }
+ void SetProcessedLocation(bool v) { plocation = v; }
+ void SetProcessedPhone(bool v) { pphone = v; }
+ void SetProcessedTool(bool v) { ptool = v; }
+ void SetProcessedNote(bool v) { pnote = v; }
+ private:
+ bool pname,pemail,plocation,pphone,ptool,pnote;
+ };
+
+ RTCPSDESInfoInternal ownsdesinfo;
+ int interval_name,interval_email,interval_location;
+ int interval_phone,interval_tool,interval_note;
+ bool doname,doemail,doloc,dophone,dotool,donote;
+ bool processingsdes;
+
+ int sdesbuildcount;
+};
+
+#endif // RTCPPACKETBUILDER_H
+
diff --git a/src/rtcprrpacket.cpp b/src/rtcprrpacket.cpp
new file mode 100644
index 0000000..42cf969
--- /dev/null
+++ b/src/rtcprrpacket.cpp
@@ -0,0 +1,94 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtcprrpacket.h"
+#ifdef RTPDEBUG
+ #include <iostream>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+RTCPRRPacket::RTCPRRPacket(uint8_t *data,size_t datalength)
+ : RTCPPacket(RR,data,datalength)
+{
+ knownformat = false;
+
+ RTCPCommonHeader *hdr;
+ size_t len = datalength;
+ size_t expectedlength;
+
+ hdr = (RTCPCommonHeader *)data;
+ if (hdr->padding)
+ {
+ uint8_t padcount = data[datalength-1];
+ if ((padcount & 0x03) != 0) // not a multiple of four! (see rfc 3550 p 37)
+ return;
+ if (((size_t)padcount) >= len)
+ return;
+ len -= (size_t)padcount;
+ }
+
+ expectedlength = sizeof(RTCPCommonHeader)+sizeof(uint32_t);
+ expectedlength += sizeof(RTCPReceiverReport)*((int)hdr->count);
+
+ if (expectedlength != len)
+ return;
+
+ knownformat = true;
+}
+
+#ifdef RTPDEBUG
+void RTCPRRPacket::Dump()
+{
+ RTCPPacket::Dump();
+ if (!IsKnownFormat())
+ std::cout << " Unknown format" << std::endl;
+ else
+ {
+ int num = GetReceptionReportCount();
+ int i;
+
+ std::cout << " SSRC of sender: " << GetSenderSSRC() << std::endl;
+ for (i = 0 ; i < num ; i++)
+ {
+ std::cout << " Report block " << i << std::endl;
+ std::cout << " SSRC: " << GetSSRC(i) << std::endl;
+ std::cout << " Fraction lost: " << (uint32_t)GetFractionLost(i) << std::endl;
+ std::cout << " Packets lost: " << GetLostPacketCount(i) << std::endl;
+ std::cout << " Seq. nr.: " << GetExtendedHighestSequenceNumber(i) << std::endl;
+ std::cout << " Jitter: " << GetJitter(i) << std::endl;
+ std::cout << " LSR: " << GetLSR(i) << std::endl;
+ std::cout << " DLSR: " << GetDLSR(i) << std::endl;
+ }
+ }
+}
+#endif // RTPDEBUG
diff --git a/src/rtcprrpacket.h b/src/rtcprrpacket.h
new file mode 100644
index 0000000..6e48f16
--- /dev/null
+++ b/src/rtcprrpacket.h
@@ -0,0 +1,201 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtcprrpacket.h
+ */
+
+#ifndef RTCPRRPACKET_H
+
+#define RTCPRRPACKET_H
+
+#include "rtpconfig.h"
+#include "rtcppacket.h"
+#include "rtpstructs.h"
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ #include <netinet/in.h>
+#endif // WIN32
+
+class RTCPCompoundPacket;
+
+/** Describes an RTCP receiver report packet. */
+class RTCPRRPacket : public RTCPPacket
+{
+public:
+ /** Creates an instance based on the data in \c data with length \c datalen.
+ * Creates an instance based on the data in \c data with length \c datalen. Since the \c data pointer
+ * is referenced inside the class (no copy of the data is made) one must make sure that the memory it points
+ * to is valid as long as the class instance exists.
+ */
+ RTCPRRPacket(uint8_t *data,size_t datalen);
+ ~RTCPRRPacket() { }
+
+ /** Returns the SSRC of the participant who sent this packet. */
+ uint32_t GetSenderSSRC() const;
+
+ /** Returns the number of reception report blocks present in this packet. */
+ int GetReceptionReportCount() const;
+
+ /** Returns the SSRC of the reception report block described by \c index which may have a value
+ * from 0 to GetReceptionReportCount()-1 (note that no check is performed to see if \c index is
+ * valid).
+ */
+ uint32_t GetSSRC(int index) const;
+
+ /** Returns the `fraction lost' field of the reception report described by \c index which may have
+ * a value from 0 to GetReceptionReportCount()-1 (note that no check is performed to see if \c index is
+ * valid).
+ */
+ uint8_t GetFractionLost(int index) const;
+
+ /** Returns the number of lost packets in the reception report block described by \c index which may have
+ * a value from 0 to GetReceptionReportCount()-1 (note that no check is performed to see if \c index is
+ * valid).
+ */
+ int32_t GetLostPacketCount(int index) const;
+
+ /** Returns the extended highest sequence number of the reception report block described by \c index which may have
+ * a value from 0 to GetReceptionReportCount()-1 (note that no check is performed to see if \c index is
+ * valid).
+ */
+ uint32_t GetExtendedHighestSequenceNumber(int index) const;
+
+ /** Returns the jitter field of the reception report block described by \c index which may have
+ * a value from 0 to GetReceptionReportCount()-1 (note that no check is performed to see if \c index is
+ * valid).
+ */
+ uint32_t GetJitter(int index) const;
+
+ /** Returns the LSR field of the reception report block described by \c index which may have
+ * a value from 0 to GetReceptionReportCount()-1 (note that no check is performed to see if \c index is
+ * valid).
+ */
+ uint32_t GetLSR(int index) const;
+
+ /** Returns the DLSR field of the reception report block described by \c index which may have
+ * a value from 0 to GetReceptionReportCount()-1 (note that no check is performed to see if \c index is
+ * valid).
+ */
+ uint32_t GetDLSR(int index) const;
+
+
+#ifdef RTPDEBUG
+ void Dump();
+#endif // RTPDEBUG
+private:
+ RTCPReceiverReport *GotoReport(int index) const;
+};
+
+inline uint32_t RTCPRRPacket::GetSenderSSRC() const
+{
+ if (!knownformat)
+ return 0;
+
+ uint32_t *ssrcptr = (uint32_t *)(data+sizeof(RTCPCommonHeader));
+ return ntohl(*ssrcptr);
+}
+inline int RTCPRRPacket::GetReceptionReportCount() const
+{
+ if (!knownformat)
+ return 0;
+ RTCPCommonHeader *hdr = (RTCPCommonHeader *)data;
+ return ((int)hdr->count);
+}
+
+inline RTCPReceiverReport *RTCPRRPacket::GotoReport(int index) const
+{
+ RTCPReceiverReport *r = (RTCPReceiverReport *)(data+sizeof(RTCPCommonHeader)+sizeof(uint32_t)+index*sizeof(RTCPReceiverReport));
+ return r;
+}
+
+inline uint32_t RTCPRRPacket::GetSSRC(int index) const
+{
+ if (!knownformat)
+ return 0;
+ RTCPReceiverReport *r = GotoReport(index);
+ return ntohl(r->ssrc);
+}
+
+inline uint8_t RTCPRRPacket::GetFractionLost(int index) const
+{
+ if (!knownformat)
+ return 0;
+ RTCPReceiverReport *r = GotoReport(index);
+ return r->fractionlost;
+}
+
+inline int32_t RTCPRRPacket::GetLostPacketCount(int index) const
+{
+ if (!knownformat)
+ return 0;
+ RTCPReceiverReport *r = GotoReport(index);
+ uint32_t count = ((uint32_t)r->packetslost[2])|(((uint32_t)r->packetslost[1])<<8)|(((uint32_t)r->packetslost[0])<<16);
+ if ((count&0x00800000) != 0) // test for negative number
+ count |= 0xFF000000;
+ int32_t *count2 = (int32_t *)(&count);
+ return (*count2);
+}
+
+inline uint32_t RTCPRRPacket::GetExtendedHighestSequenceNumber(int index) const
+{
+ if (!knownformat)
+ return 0;
+ RTCPReceiverReport *r = GotoReport(index);
+ return ntohl(r->exthighseqnr);
+}
+
+inline uint32_t RTCPRRPacket::GetJitter(int index) const
+{
+ if (!knownformat)
+ return 0;
+ RTCPReceiverReport *r = GotoReport(index);
+ return ntohl(r->jitter);
+}
+
+inline uint32_t RTCPRRPacket::GetLSR(int index) const
+{
+ if (!knownformat)
+ return 0;
+ RTCPReceiverReport *r = GotoReport(index);
+ return ntohl(r->lsr);
+}
+
+inline uint32_t RTCPRRPacket::GetDLSR(int index) const
+{
+ if (!knownformat)
+ return 0;
+ RTCPReceiverReport *r = GotoReport(index);
+ return ntohl(r->dlsr);
+}
+
+#endif // RTCPRRPACKET_H
+
diff --git a/src/rtcpscheduler.cpp b/src/rtcpscheduler.cpp
new file mode 100644
index 0000000..fa8510f
--- /dev/null
+++ b/src/rtcpscheduler.cpp
@@ -0,0 +1,416 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtcpscheduler.h"
+#include "rtpsources.h"
+#include "rtpdefines.h"
+#include "rtcppacket.h"
+#include "rtppacket.h"
+#include "rtcpcompoundpacket.h"
+#include "rtpsourcedata.h"
+
+#include "rtpdebug.h"
+
+#define RTCPSCHED_MININTERVAL 1.0
+
+RTCPSchedulerParams::RTCPSchedulerParams() : mininterval(RTCP_DEFAULTMININTERVAL)
+{
+ bandwidth = 1000; // TODO What is a good value here?
+ senderfraction = RTCP_DEFAULTSENDERFRACTION;
+ usehalfatstartup = RTCP_DEFAULTHALFATSTARTUP;
+ immediatebye = RTCP_DEFAULTIMMEDIATEBYE;
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ timeinit.Dummy();
+#endif // WIN32 || _WIN32_WCE
+}
+
+RTCPSchedulerParams::~RTCPSchedulerParams()
+{
+}
+
+int RTCPSchedulerParams::SetRTCPBandwidth(double bw)
+{
+ if (bw < 0.0)
+ return ERR_RTP_SCHEDPARAMS_INVALIDBANDWIDTH;
+ bandwidth = bw;
+ return 0;
+}
+
+int RTCPSchedulerParams::SetSenderBandwidthFraction(double fraction)
+{
+ if (fraction < 0.0 || fraction > 1.0)
+ return ERR_RTP_SCHEDPARAMS_BADFRACTION;
+ senderfraction = fraction;
+ return 0;
+}
+
+int RTCPSchedulerParams::SetMinimumTransmissionInterval(const RTPTime &t)
+{
+ double t2 = t.GetDouble();
+
+ if (t2 < RTCPSCHED_MININTERVAL)
+ return ERR_RTP_SCHEDPARAMS_BADMINIMUMINTERVAL;
+
+ mininterval = t;
+ return 0;
+}
+
+RTCPScheduler::RTCPScheduler(RTPSources &s) : sources(s),nextrtcptime(0,0),prevrtcptime(0,0)
+{
+ Reset();
+}
+
+RTCPScheduler::~RTCPScheduler()
+{
+}
+
+void RTCPScheduler::Reset()
+{
+ headeroverhead = 0; // user has to set this to an appropriate value
+ hassentrtcp = false;
+ firstcall = true;
+ avgrtcppacksize = 1000; // TODO: what is a good value for this?
+ byescheduled = false;
+ sendbyenow = false;
+}
+
+void RTCPScheduler::AnalyseIncoming(RTCPCompoundPacket &rtcpcomppack)
+{
+ bool isbye = false;
+ RTCPPacket *p;
+
+ rtcpcomppack.GotoFirstPacket();
+ while (!isbye && ((p = rtcpcomppack.GetNextPacket()) != 0))
+ {
+ if (p->GetPacketType() == RTCPPacket::BYE)
+ isbye = true;
+ }
+
+ if (!isbye)
+ {
+ size_t packsize = headeroverhead+rtcpcomppack.GetCompoundPacketLength();
+ avgrtcppacksize = (size_t)((1.0/16.0)*((double)packsize)+(15.0/16.0)*((double)avgrtcppacksize));
+ }
+ else
+ {
+ if (byescheduled)
+ {
+ size_t packsize = headeroverhead+rtcpcomppack.GetCompoundPacketLength();
+ avgbyepacketsize = (size_t)((1.0/16.0)*((double)packsize)+(15.0/16.0)*((double)avgbyepacketsize));
+ byemembers++;
+ }
+ }
+}
+
+void RTCPScheduler::AnalyseOutgoing(RTCPCompoundPacket &rtcpcomppack)
+{
+ bool isbye = false;
+ RTCPPacket *p;
+
+ rtcpcomppack.GotoFirstPacket();
+ while (!isbye && ((p = rtcpcomppack.GetNextPacket()) != 0))
+ {
+ if (p->GetPacketType() == RTCPPacket::BYE)
+ isbye = true;
+ }
+
+ if (!isbye)
+ {
+ size_t packsize = headeroverhead+rtcpcomppack.GetCompoundPacketLength();
+ avgrtcppacksize = (size_t)((1.0/16.0)*((double)packsize)+(15.0/16.0)*((double)avgrtcppacksize));
+ }
+
+ hassentrtcp = true;
+}
+
+RTPTime RTCPScheduler::GetTransmissionDelay()
+{
+ if (firstcall)
+ {
+ firstcall = false;
+ prevrtcptime = RTPTime::CurrentTime();
+ pmembers = sources.GetActiveMemberCount();
+ CalculateNextRTCPTime();
+ }
+
+ RTPTime curtime = RTPTime::CurrentTime();
+
+ if (curtime > nextrtcptime) // packet should be sent
+ return RTPTime(0,0);
+
+ RTPTime diff = nextrtcptime;
+ diff -= curtime;
+
+ return diff;
+}
+
+bool RTCPScheduler::IsTime()
+{
+ if (firstcall)
+ {
+ firstcall = false;
+ prevrtcptime = RTPTime::CurrentTime();
+ pmembers = sources.GetActiveMemberCount();
+ CalculateNextRTCPTime();
+ return false;
+ }
+
+ RTPTime currenttime = RTPTime::CurrentTime();
+
+// // TODO: for debugging
+// double diff = nextrtcptime.GetDouble() - currenttime.GetDouble();
+//
+// std::cout << "Delay till next RTCP interval: " << diff << std::endl;
+
+ if (currenttime < nextrtcptime) // timer has not yet expired
+ return false;
+
+ RTPTime checktime(0,0);
+
+ if (!byescheduled)
+ {
+ bool aresender = false;
+ RTPSourceData *srcdat;
+
+ if ((srcdat = sources.GetOwnSourceInfo()) != 0)
+ aresender = srcdat->IsSender();
+
+ checktime = CalculateTransmissionInterval(aresender);
+ }
+ else
+ checktime = CalculateBYETransmissionInterval();
+
+// std::cout << "Calculated checktime: " << checktime.GetDouble() << std::endl;
+
+ checktime += prevrtcptime;
+
+ if (checktime <= currenttime) // Okay
+ {
+ byescheduled = false;
+ prevrtcptime = currenttime;
+ pmembers = sources.GetActiveMemberCount();
+ CalculateNextRTCPTime();
+ return true;
+ }
+
+// std::cout << "New delay: " << nextrtcptime.GetDouble() - currenttime.GetDouble() << std::endl;
+
+ nextrtcptime = checktime;
+ pmembers = sources.GetActiveMemberCount();
+
+ return false;
+}
+
+void RTCPScheduler::CalculateNextRTCPTime()
+{
+ bool aresender = false;
+ RTPSourceData *srcdat;
+
+ if ((srcdat = sources.GetOwnSourceInfo()) != 0)
+ aresender = srcdat->IsSender();
+
+ nextrtcptime = RTPTime::CurrentTime();
+ nextrtcptime += CalculateTransmissionInterval(aresender);
+}
+
+RTPTime RTCPScheduler::CalculateDeterministicInterval(bool sender /* = false */)
+{
+ int numsenders = sources.GetSenderCount();
+ int numtotal = sources.GetActiveMemberCount();
+
+// std::cout << "CalculateDeterministicInterval" << std::endl;
+// std::cout << " numsenders: " << numsenders << std::endl;
+// std::cout << " numtotal: " << numtotal << std::endl;
+
+ // Try to avoid division by zero:
+ if (numtotal == 0)
+ numtotal++;
+
+ double sfraction = ((double)numsenders)/((double)numtotal);
+ double C,n;
+
+ if (sfraction <= schedparams.GetSenderBandwidthFraction())
+ {
+ if (sender)
+ {
+ C = ((double)avgrtcppacksize)/(schedparams.GetSenderBandwidthFraction()*schedparams.GetRTCPBandwidth());
+ n = (double)numsenders;
+ }
+ else
+ {
+ C = ((double)avgrtcppacksize)/((1.0-schedparams.GetSenderBandwidthFraction())*schedparams.GetRTCPBandwidth());
+ n = (double)(numtotal-numsenders);
+ }
+ }
+ else
+ {
+ C = ((double)avgrtcppacksize)/schedparams.GetRTCPBandwidth();
+ n = (double)numtotal;
+ }
+
+ RTPTime Tmin = schedparams.GetMinimumTransmissionInterval();
+ double tmin = Tmin.GetDouble();
+
+ if (!hassentrtcp && schedparams.GetUseHalfAtStartup())
+ tmin /= 2.0;
+
+ double ntimesC = n*C;
+ double Td = (tmin>ntimesC)?tmin:ntimesC;
+
+ // TODO: for debugging
+// std::cout << " Td: " << Td << std::endl;
+
+ return RTPTime(Td);
+}
+
+RTPTime RTCPScheduler::CalculateTransmissionInterval(bool sender)
+{
+ RTPTime Td = CalculateDeterministicInterval(sender);
+ double td,mul,T;
+
+// std::cout << "CalculateTransmissionInterval" << std::endl;
+
+ td = Td.GetDouble();
+ mul = rtprand.GetRandomDouble()+0.5; // gives random value between 0.5 and 1.5
+ T = (td*mul)/1.21828; // see RFC 3550 p 30
+
+// std::cout << " Td: " << td << std::endl;
+// std::cout << " mul: " << mul << std::endl;
+// std::cout << " T: " << T << std::endl;
+
+ return RTPTime(T);
+}
+
+void RTCPScheduler::PerformReverseReconsideration()
+{
+ if (firstcall)
+ return;
+
+ double diff1,diff2;
+ int members = sources.GetActiveMemberCount();
+
+ RTPTime tc = RTPTime::CurrentTime();
+ RTPTime tn_min_tc = nextrtcptime;
+
+ if (tn_min_tc > tc)
+ tn_min_tc -= tc;
+ else
+ tn_min_tc = RTPTime(0,0);
+
+// std::cout << "+tn_min_tc0 " << nextrtcptime.GetDouble()-tc.GetDouble() << std::endl;
+// std::cout << "-tn_min_tc0 " << -nextrtcptime.GetDouble()+tc.GetDouble() << std::endl;
+// std::cout << "tn_min_tc " << tn_min_tc.GetDouble() << std::endl;
+
+ RTPTime tc_min_tp = tc;
+
+ if (tc_min_tp > prevrtcptime)
+ tc_min_tp -= prevrtcptime;
+ else
+ tc_min_tp = 0;
+
+ if (pmembers == 0) // avoid division by zero
+ pmembers++;
+
+ diff1 = (((double)members)/((double)pmembers))*tn_min_tc.GetDouble();
+ diff2 = (((double)members)/((double)pmembers))*tc_min_tp.GetDouble();
+
+ nextrtcptime = tc;
+ prevrtcptime = tc;
+ nextrtcptime += RTPTime(diff1);
+ prevrtcptime -= RTPTime(diff2);
+
+ pmembers = members;
+}
+
+void RTCPScheduler::ScheduleBYEPacket(size_t packetsize)
+{
+ if (byescheduled)
+ return;
+
+ if (firstcall)
+ {
+ firstcall = false;
+ pmembers = sources.GetActiveMemberCount();
+ }
+
+ byescheduled = true;
+ avgbyepacketsize = packetsize+headeroverhead;
+
+ // For now, we will always use the BYE backoff algorithm as described in rfc 3550 p 33
+
+ byemembers = 1;
+ pbyemembers = 1;
+
+ if (schedparams.GetRequestImmediateBYE() && sources.GetActiveMemberCount() < 50) // p 34 (top)
+ sendbyenow = true;
+ else
+ sendbyenow = false;
+
+ prevrtcptime = RTPTime::CurrentTime();
+ nextrtcptime = prevrtcptime;
+ nextrtcptime += CalculateBYETransmissionInterval();
+}
+
+void RTCPScheduler::ActiveMemberDecrease()
+{
+ if (sources.GetActiveMemberCount() < pmembers)
+ PerformReverseReconsideration();
+}
+
+RTPTime RTCPScheduler::CalculateBYETransmissionInterval()
+{
+ if (!byescheduled)
+ return RTPTime(0,0);
+
+ if (sendbyenow)
+ return RTPTime(0,0);
+
+ double C,n;
+
+ C = ((double)avgbyepacketsize)/((1.0-schedparams.GetSenderBandwidthFraction())*schedparams.GetRTCPBandwidth());
+ n = (double)byemembers;
+
+ RTPTime Tmin = schedparams.GetMinimumTransmissionInterval();
+ double tmin = Tmin.GetDouble();
+
+ if (schedparams.GetUseHalfAtStartup())
+ tmin /= 2.0;
+
+ double ntimesC = n*C;
+ double Td = (tmin>ntimesC)?tmin:ntimesC;
+
+ double mul = rtprand.GetRandomDouble()+0.5; // gives random value between 0.5 and 1.5
+ double T = (Td*mul)/1.21828; // see RFC 3550 p 30
+
+ return RTPTime(T);
+}
+
diff --git a/src/rtcpscheduler.h b/src/rtcpscheduler.h
new file mode 100644
index 0000000..e5736a3
--- /dev/null
+++ b/src/rtcpscheduler.h
@@ -0,0 +1,183 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtcpscheduler.h
+ */
+
+#ifndef RTCPSCHEDULER_H
+
+#define RTCPSCHEDULER_H
+
+#include "rtpconfig.h"
+#include "rtptimeutilities.h"
+#include "rtprandom.h"
+
+class RTCPCompoundPacket;
+class RTPPacket;
+class RTPSources;
+
+/** Describes parameters used by the RTCPScheduler class. */
+class RTCPSchedulerParams
+{
+public:
+ RTCPSchedulerParams();
+ ~RTCPSchedulerParams();
+
+ /** Sets the RTCP bandwidth to be used to \c bw (in bytes per second). */
+ int SetRTCPBandwidth(double bw);
+
+ /** Returns the used RTCP bandwidth in bytes per second (default is 1000). */
+ double GetRTCPBandwidth() const { return bandwidth; }
+
+ /** Sets the fraction of the RTCP bandwidth reserved for senders to \c fraction. */
+ int SetSenderBandwidthFraction(double fraction);
+
+ /** Returns the fraction of the RTCP bandwidth reserved for senders (default is 25%). */
+ double GetSenderBandwidthFraction() const { return senderfraction; }
+
+ /** Sets the minimum (deterministic) interval between RTCP compound packets to \c t. */
+ int SetMinimumTransmissionInterval(const RTPTime &t);
+
+ /** Returns the minimum RTCP transmission interval (default is 5 seconds). */
+ RTPTime GetMinimumTransmissionInterval() const { return mininterval; }
+
+ /** If \c usehalf is \c true, only use half the minimum interval before sending the first RTCP compound packet. */
+ void SetUseHalfAtStartup(bool usehalf) { usehalfatstartup = usehalf; }
+
+ /** Returns \c true if only half the minimum interval should be used before sending the first RTCP compound packet
+ * (defualt is \c true).
+ */
+ bool GetUseHalfAtStartup() const { return usehalfatstartup; }
+
+ /** If \c v is \c true, the scheduler will schedule a BYE packet to be sent immediately if allowed. */
+ void SetRequestImmediateBYE(bool v) { immediatebye = v; }
+
+ /** Returns if the scheduler will schedule a BYE packet to be sent immediately if allowed
+ * (default is \c true).
+ */
+ bool GetRequestImmediateBYE() const { return immediatebye; }
+private:
+ double bandwidth;
+ double senderfraction;
+ RTPTime mininterval;
+ bool usehalfatstartup;
+ bool immediatebye;
+};
+
+/** This class determines when RTCP compound packets should be sent. */
+class RTCPScheduler
+{
+public:
+ /** Creates an instance which will use the source table RTPSources to determine when RTCP compound
+ * packets should be scheduled.
+ * Creates an instance which will use the source table RTPSources to determine when RTCP compound
+ * packets should be scheduled. Note that for correct operation the \c sources instance should have information
+ * about the own SSRC (added by RTPSources::CreateOwnSSRC).
+ */
+ RTCPScheduler(RTPSources &sources);
+ ~RTCPScheduler();
+
+ /** Resets the scheduler. */
+ void Reset();
+
+ /** Sets the scheduler parameters to be used to \c params. */
+ void SetParameters(const RTCPSchedulerParams &params) { schedparams = params; }
+
+ /** Returns the currently used scheduler parameters. */
+ RTCPSchedulerParams GetParameters() const { return schedparams; }
+
+ /** Sets the header overhead from underlying protocols (for example UDP and IP) to \c numbytes. */
+ void SetHeaderOverhead(size_t numbytes) { headeroverhead = numbytes; }
+
+ /** Returns the currently used header overhead. */
+ size_t GetHeaderOverhead() const { return headeroverhead; }
+
+ /** For each incoming RTCP compound packet, this function has to be called for the scheduler to work correctly. */
+ void AnalyseIncoming(RTCPCompoundPacket &rtcpcomppack);
+
+ /** For each outgoing RTCP compound packet, this function has to be called for the scheduler to work correctly. */
+ void AnalyseOutgoing(RTCPCompoundPacket &rtcpcomppack);
+
+ /** This function has to be called each time a member times out or sends a BYE packet. */
+ void ActiveMemberDecrease();
+
+ /** Asks the scheduler to schedule an RTCP compound packet containing a BYE packetl; the compound packet
+ * has size \c packetsize.
+ */
+ void ScheduleBYEPacket(size_t packetsize);
+
+ /** Returns the delay after which an RTCP compound will possibly have to be sent.
+ * Returns the delay after which an RTCP compound will possibly have to be sent. The IsTime member function
+ * should be called afterwards to make sure that it actually is time to send an RTCP compound packet.
+ */
+ RTPTime GetTransmissionDelay();
+
+ /** This function returns \c true if it's time to send an RTCP compound packet and \c false otherwise.
+ * This function returns \c true if it's time to send an RTCP compound packet and \c false otherwise.
+ * If the function returns \c true, it will also have calculated the next time at which a packet should
+ * be sent, so if it is called again right away, it will return \c false.
+ */
+ bool IsTime();
+
+ /** Calculates the deterministic interval at this time.
+ * Calculates the deterministic interval at this time. This is used - in combination with a certain multiplier -
+ * to time out members, senders etc.
+ */
+ RTPTime CalculateDeterministicInterval(bool sender = false);
+private:
+ void CalculateNextRTCPTime();
+ void PerformReverseReconsideration();
+ RTPTime CalculateBYETransmissionInterval();
+ RTPTime CalculateTransmissionInterval(bool sender);
+
+ RTPSources &sources;
+ RTCPSchedulerParams schedparams;
+ size_t headeroverhead;
+ size_t avgrtcppacksize;
+ bool hassentrtcp;
+ bool firstcall;
+ RTPTime nextrtcptime;
+ RTPTime prevrtcptime;
+ int pmembers;
+
+ // for BYE packet scheduling
+ bool byescheduled;
+ int byemembers,pbyemembers;
+ size_t avgbyepacketsize;
+ bool sendbyenow;
+
+ RTPRandom rtprand;
+};
+
+#endif // RTCPSCHEDULER_H
+
diff --git a/src/rtcpsdesinfo.cpp b/src/rtcpsdesinfo.cpp
new file mode 100644
index 0000000..c2611c4
--- /dev/null
+++ b/src/rtcpsdesinfo.cpp
@@ -0,0 +1,177 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtcpsdesinfo.h"
+
+#include "rtpdebug.h"
+
+void RTCPSDESInfo::Clear()
+{
+#ifdef RTP_SUPPORT_SDESPRIV
+ std::list<SDESPrivateItem *>::const_iterator it;
+
+ for (it = privitems.begin() ; it != privitems.end() ; ++it)
+ RTPDelete(*it,GetMemoryManager());
+ privitems.clear();
+#endif // RTP_SUPPORT_SDESPRIV
+}
+
+#ifdef RTP_SUPPORT_SDESPRIV
+int RTCPSDESInfo::SetPrivateValue(const uint8_t *prefix,size_t prefixlen,const uint8_t *value,size_t valuelen)
+{
+ std::list<SDESPrivateItem *>::const_iterator it;
+ bool found;
+
+ found = false;
+ it = privitems.begin();
+ while (!found && it != privitems.end())
+ {
+ uint8_t *p;
+ size_t l;
+
+ p = (*it)->GetPrefix(&l);
+ if (l == prefixlen)
+ {
+ if (l <= 0)
+ found = true;
+ else if (memcmp(prefix,p,l) == 0)
+ found = true;
+ else
+ ++it;
+ }
+ else
+ ++it;
+ }
+
+ SDESPrivateItem *item;
+
+ if (found) // replace the value for this entry
+ item = *it;
+ else // no entry for this prefix found... add it
+ {
+ if (privitems.size() >= RTP_MAXPRIVITEMS) // too many items present, just ignore it
+ return ERR_RTP_SDES_MAXPRIVITEMS;
+
+ int status;
+
+ item = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_SDESPRIVATEITEM) SDESPrivateItem(GetMemoryManager());
+ if (item == 0)
+ return ERR_RTP_OUTOFMEM;
+ if ((status = item->SetPrefix(prefix,prefixlen)) < 0)
+ {
+ RTPDelete(item,GetMemoryManager());
+ return status;
+ }
+ privitems.push_front(item);
+ }
+ return item->SetInfo(value,valuelen);
+}
+
+int RTCPSDESInfo::DeletePrivatePrefix(const uint8_t *prefix,size_t prefixlen)
+{
+ std::list<SDESPrivateItem *>::iterator it;
+ bool found;
+
+ found = false;
+ it = privitems.begin();
+ while (!found && it != privitems.end())
+ {
+ uint8_t *p;
+ size_t l;
+
+ p = (*it)->GetPrefix(&l);
+ if (l == prefixlen)
+ {
+ if (l <= 0)
+ found = true;
+ else if (memcmp(prefix,p,l) == 0)
+ found = true;
+ else
+ ++it;
+ }
+ else
+ ++it;
+ }
+ if (!found)
+ return ERR_RTP_SDES_PREFIXNOTFOUND;
+
+ RTPDelete(*it,GetMemoryManager());
+ privitems.erase(it);
+ return 0;
+}
+
+void RTCPSDESInfo::GotoFirstPrivateValue()
+{
+ curitem = privitems.begin();
+}
+
+bool RTCPSDESInfo::GetNextPrivateValue(uint8_t **prefix,size_t *prefixlen,uint8_t **value,size_t *valuelen)
+{
+ if (curitem == privitems.end())
+ return false;
+ *prefix = (*curitem)->GetPrefix(prefixlen);
+ *value = (*curitem)->GetInfo(valuelen);
+ ++curitem;
+ return true;
+}
+
+bool RTCPSDESInfo::GetPrivateValue(const uint8_t *prefix,size_t prefixlen,uint8_t **value,size_t *valuelen) const
+{
+ std::list<SDESPrivateItem *>::const_iterator it;
+ bool found;
+
+ found = false;
+ it = privitems.begin();
+ while (!found && it != privitems.end())
+ {
+ uint8_t *p;
+ size_t l;
+
+ p = (*it)->GetPrefix(&l);
+ if (l == prefixlen)
+ {
+ if (l <= 0)
+ found = true;
+ else if (memcmp(prefix,p,l) == 0)
+ found = true;
+ else
+ ++it;
+ }
+ else
+ ++it;
+ }
+ if (found)
+ *value = (*it)->GetInfo(valuelen);
+ return found;
+}
+#endif // RTP_SUPPORT_SDESPRIV
+
diff --git a/src/rtcpsdesinfo.h b/src/rtcpsdesinfo.h
new file mode 100644
index 0000000..f96915a
--- /dev/null
+++ b/src/rtcpsdesinfo.h
@@ -0,0 +1,215 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtcpsdesinfo.h
+ */
+
+#ifndef RTCPSDESINFO_H
+
+#define RTCPSDESINFO_H
+
+#include "rtpconfig.h"
+#include "rtperrors.h"
+#include "rtpdefines.h"
+#include "rtptypes.h"
+#include "rtpmemoryobject.h"
+#include <string.h>
+#include <list>
+
+/** The class RTCPSDESInfo is a container for RTCP SDES information. */
+class RTCPSDESInfo : public RTPMemoryObject
+{
+public:
+ /** Constructs an instance, optionally installing a memory manager. */
+ RTCPSDESInfo(RTPMemoryManager *mgr = 0) : RTPMemoryObject(mgr) { for (int i = 0 ; i < RTCP_SDES_NUMITEMS_NONPRIVATE ; i++) nonprivateitems[i].SetMemoryManager(mgr); }
+ virtual ~RTCPSDESInfo() { Clear(); }
+
+ /** Clears all SDES information. */
+ void Clear();
+
+ /** Sets the SDES CNAME item to \c s with length \c l. */
+ int SetCNAME(const uint8_t *s,size_t l) { return SetNonPrivateItem(RTCP_SDES_ID_CNAME-1,s,l); }
+
+ /** Sets the SDES name item to \c s with length \c l. */
+ int SetName(const uint8_t *s,size_t l) { return SetNonPrivateItem(RTCP_SDES_ID_NAME-1,s,l); }
+
+ /** Sets the SDES e-mail item to \c s with length \c l. */
+ int SetEMail(const uint8_t *s,size_t l) { return SetNonPrivateItem(RTCP_SDES_ID_EMAIL-1,s,l); }
+
+ /** Sets the SDES phone item to \c s with length \c l. */
+ int SetPhone(const uint8_t *s,size_t l) { return SetNonPrivateItem(RTCP_SDES_ID_PHONE-1,s,l); }
+
+ /** Sets the SDES location item to \c s with length \c l. */
+ int SetLocation(const uint8_t *s,size_t l) { return SetNonPrivateItem(RTCP_SDES_ID_LOCATION-1,s,l); }
+
+ /** Sets the SDES tool item to \c s with length \c l. */
+ int SetTool(const uint8_t *s,size_t l) { return SetNonPrivateItem(RTCP_SDES_ID_TOOL-1,s,l); }
+
+ /** Sets the SDES note item to \c s with length \c l. */
+ int SetNote(const uint8_t *s,size_t l) { return SetNonPrivateItem(RTCP_SDES_ID_NOTE-1,s,l); }
+
+#ifdef RTP_SUPPORT_SDESPRIV
+ /** Sets the entry for the prefix string specified by \c prefix with length \c prefixlen to contain
+ * the value string specified by \c value with length \c valuelen (if the maximum allowed
+ * number of prefixes was reached, the error code \c ERR_RTP_SDES_MAXPRIVITEMS is returned.
+ */
+ int SetPrivateValue(const uint8_t *prefix,size_t prefixlen,const uint8_t *value,size_t valuelen);
+
+ /** Deletes the entry for the prefix specified by \c s with length \c len. */
+ int DeletePrivatePrefix(const uint8_t *s,size_t len);
+#endif // RTP_SUPPORT_SDESPRIV
+
+ /** Returns the SDES CNAME item and stores its length in \c len. */
+ uint8_t *GetCNAME(size_t *len) const { return GetNonPrivateItem(RTCP_SDES_ID_CNAME-1,len); }
+
+ /** Returns the SDES name item and stores its length in \c len. */
+ uint8_t *GetName(size_t *len) const { return GetNonPrivateItem(RTCP_SDES_ID_NAME-1,len); }
+
+ /** Returns the SDES e-mail item and stores its length in \c len. */
+ uint8_t *GetEMail(size_t *len) const { return GetNonPrivateItem(RTCP_SDES_ID_EMAIL-1,len); }
+
+ /** Returns the SDES phone item and stores its length in \c len. */
+ uint8_t *GetPhone(size_t *len) const { return GetNonPrivateItem(RTCP_SDES_ID_PHONE-1,len); }
+
+ /** Returns the SDES location item and stores its length in \c len. */
+ uint8_t *GetLocation(size_t *len) const { return GetNonPrivateItem(RTCP_SDES_ID_LOCATION-1,len); }
+
+ /** Returns the SDES tool item and stores its length in \c len. */
+ uint8_t *GetTool(size_t *len) const { return GetNonPrivateItem(RTCP_SDES_ID_TOOL-1,len); }
+
+ /** Returns the SDES note item and stores its length in \c len. */
+ uint8_t *GetNote(size_t *len) const { return GetNonPrivateItem(RTCP_SDES_ID_NOTE-1,len); }
+#ifdef RTP_SUPPORT_SDESPRIV
+ /** Starts the iteration over the stored SDES private item prefixes and their associated values. */
+ void GotoFirstPrivateValue();
+
+ /** Returns SDES priv item information.
+ * If available, returns \c true and stores the next SDES
+ * private item prefix in \c prefix and its length in
+ * \c prefixlen. The associated value and its length are
+ * then stored in \c value and \c valuelen. Otherwise,
+ * it returns \c false.
+ */
+ bool GetNextPrivateValue(uint8_t **prefix,size_t *prefixlen,uint8_t **value,size_t *valuelen);
+
+ /** Returns SDES priv item information.
+ * Looks for the entry which corresponds to the SDES private
+ * item prefix \c prefix with length \c prefixlen. If found,
+ * the function returns \c true and stores the associated
+ * value and its length in \c value and \c valuelen
+ * respectively.
+ */
+ bool GetPrivateValue(const uint8_t *prefix,size_t prefixlen,uint8_t **value,size_t *valuelen) const;
+#endif // RTP_SUPPORT_SDESPRIV
+private:
+ int SetNonPrivateItem(int itemno,const uint8_t *s,size_t l) { if (l > RTCP_SDES_MAXITEMLENGTH) return ERR_RTP_SDES_LENGTHTOOBIG; return nonprivateitems[itemno].SetInfo(s,l); }
+ uint8_t *GetNonPrivateItem(int itemno,size_t *len) const { return nonprivateitems[itemno].GetInfo(len); }
+
+ class SDESItem : public RTPMemoryObject
+ {
+ public:
+ SDESItem(RTPMemoryManager *mgr = 0) : RTPMemoryObject(mgr)
+ {
+ str = 0;
+ length = 0;
+ }
+ void SetMemoryManager(RTPMemoryManager *mgr)
+ {
+ RTPMemoryObject::SetMemoryManager(mgr);
+ }
+ ~SDESItem()
+ {
+ if (str)
+ RTPDeleteByteArray(str,GetMemoryManager());
+ }
+ uint8_t *GetInfo(size_t *len) const { *len = length; return str; }
+ int SetInfo(const uint8_t *s,size_t len) { return SetString(&str,&length,s,len); }
+ protected:
+ int SetString(uint8_t **dest,size_t *destlen,const uint8_t *s,size_t len)
+ {
+ if (len <= 0)
+ {
+ if (*dest)
+ RTPDeleteByteArray((*dest),GetMemoryManager());
+ *dest = 0;
+ *destlen = 0;
+ }
+ else
+ {
+ len = (len>RTCP_SDES_MAXITEMLENGTH)?RTCP_SDES_MAXITEMLENGTH:len;
+ uint8_t *str2 = RTPNew(GetMemoryManager(),RTPMEM_TYPE_BUFFER_SDESITEM) uint8_t[len];
+ if (str2 == 0)
+ return ERR_RTP_OUTOFMEM;
+ memcpy(str2,s,len);
+ *destlen = len;
+ if (*dest)
+ RTPDeleteByteArray((*dest),GetMemoryManager());
+ *dest = str2;
+ }
+ return 0;
+ }
+ private:
+ uint8_t *str;
+ size_t length;
+ };
+
+ SDESItem nonprivateitems[RTCP_SDES_NUMITEMS_NONPRIVATE];
+
+#ifdef RTP_SUPPORT_SDESPRIV
+ class SDESPrivateItem : public SDESItem
+ {
+ public:
+ SDESPrivateItem(RTPMemoryManager *mgr) : SDESItem(mgr)
+ {
+ prefixlen = 0;
+ prefix = 0;
+ }
+ ~SDESPrivateItem()
+ {
+ if (prefix)
+ RTPDeleteByteArray(prefix,GetMemoryManager());
+ }
+ uint8_t *GetPrefix(size_t *len) const { *len = prefixlen; return prefix; }
+ int SetPrefix(const uint8_t *s,size_t len) { return SetString(&prefix,&prefixlen,s,len); }
+ private:
+ uint8_t *prefix;
+ size_t prefixlen;
+ };
+
+ std::list<SDESPrivateItem *> privitems;
+ std::list<SDESPrivateItem *>::const_iterator curitem;
+#endif // RTP_SUPPORT_SDESPRIV
+};
+
+#endif // RTCPSDESINFO_H
+
diff --git a/src/rtcpsdespacket.cpp b/src/rtcpsdespacket.cpp
new file mode 100644
index 0000000..798f83c
--- /dev/null
+++ b/src/rtcpsdespacket.cpp
@@ -0,0 +1,230 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtcpsdespacket.h"
+#ifdef RTPDEBUG
+ #include <iostream>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+RTCPSDESPacket::RTCPSDESPacket(uint8_t *data,size_t datalength)
+ : RTCPPacket(SDES,data,datalength)
+{
+ knownformat = false;
+ currentchunk = 0;
+ itemoffset = 0;
+ curchunknum = 0;
+
+ RTCPCommonHeader *hdr = (RTCPCommonHeader *)data;
+ size_t len = datalength;
+
+ if (hdr->padding)
+ {
+ uint8_t padcount = data[datalength-1];
+ if ((padcount & 0x03) != 0) // not a multiple of four! (see rfc 3550 p 37)
+ return;
+ if (((size_t)padcount) >= len)
+ return;
+ len -= (size_t)padcount;
+ }
+
+ if (hdr->count == 0)
+ {
+ if (len != sizeof(RTCPCommonHeader))
+ return;
+ }
+ else
+ {
+ int ssrccount = (int)(hdr->count);
+ uint8_t *chunk;
+ int chunkoffset;
+
+ if (len < sizeof(RTCPCommonHeader))
+ return;
+
+ len -= sizeof(RTCPCommonHeader);
+ chunk = data+sizeof(RTCPCommonHeader);
+
+ while ((ssrccount > 0) && (len > 0))
+ {
+ chunkoffset = 0;
+
+ if (len < (sizeof(uint32_t)*2)) // chunk must contain at least a SSRC identifier
+ return; // and a (possibly empty) item
+
+ len -= sizeof(uint32_t);
+ chunkoffset = sizeof(uint32_t);
+
+ bool done = false;
+ while (!done)
+ {
+ if (len < 1) // at least a zero byte (end of item list) should be there
+ return;
+
+ RTCPSDESHeader *sdeshdr = (RTCPSDESHeader *)(chunk+chunkoffset);
+ if (sdeshdr->sdesid == 0) // end of item list
+ {
+ len--;
+ chunkoffset++;
+
+ size_t r = (chunkoffset&0x03);
+ if (r != 0)
+ {
+ size_t addoffset = 4-r;
+
+ if (addoffset > len)
+ return;
+ len -= addoffset;
+ chunkoffset += addoffset;
+ }
+ done = true;
+ }
+ else
+ {
+ if (len < sizeof(RTCPSDESHeader))
+ return;
+
+ len -= sizeof(RTCPSDESHeader);
+ chunkoffset += sizeof(RTCPSDESHeader);
+
+ size_t itemlen = (size_t)(sdeshdr->length);
+ if (itemlen > len)
+ return;
+
+ len -= itemlen;
+ chunkoffset += itemlen;
+ }
+ }
+
+ ssrccount--;
+ chunk += chunkoffset;
+ }
+
+ // check for remaining bytes
+ if (len > 0)
+ return;
+ if (ssrccount > 0)
+ return;
+ }
+
+ knownformat = true;
+}
+
+#ifdef RTPDEBUG
+void RTCPSDESPacket::Dump()
+{
+ RTCPPacket::Dump();
+ if (!IsKnownFormat())
+ {
+ std::cout << " Unknown format" << std::endl;
+ return;
+ }
+ if (!GotoFirstChunk())
+ {
+ std::cout << " No chunks present" << std::endl;
+ return;
+ }
+
+ do
+ {
+ std::cout << " SDES Chunk for SSRC: " << GetChunkSSRC() << std::endl;
+ if (!GotoFirstItem())
+ std::cout << " No items found" << std::endl;
+ else
+ {
+ do
+ {
+ std::cout << " ";
+ switch (GetItemType())
+ {
+ case None:
+ std::cout << "None ";
+ break;
+ case CNAME:
+ std::cout << "CNAME ";
+ break;
+ case NAME:
+ std::cout << "NAME ";
+ break;
+ case EMAIL:
+ std::cout << "EMAIL ";
+ break;
+ case PHONE:
+ std::cout << "PHONE ";
+ break;
+ case LOC:
+ std::cout << "LOC ";
+ break;
+ case TOOL:
+ std::cout << "TOOL ";
+ break;
+ case NOTE:
+ std::cout << "NOTE ";
+ break;
+ case PRIV:
+ std::cout << "PRIV ";
+ break;
+ case Unknown:
+ default:
+ std::cout << "Unknown ";
+ }
+
+ std::cout << "Length: " << GetItemLength() << std::endl;
+
+ if (GetItemType() != PRIV)
+ {
+ char str[1024];
+ memcpy(str,GetItemData(),GetItemLength());
+ str[GetItemLength()] = 0;
+ std::cout << " Value: " << str << std::endl;
+ }
+#ifdef RTP_SUPPORT_SDESPRIV
+ else // PRIV item
+ {
+ char str[1024];
+ memcpy(str,GetPRIVPrefixData(),GetPRIVPrefixLength());
+ str[GetPRIVPrefixLength()] = 0;
+ std::cout << " Prefix: " << str << std::endl;
+ std::cout << " Length: " << GetPRIVPrefixLength() << std::endl;
+ memcpy(str,GetPRIVValueData(),GetPRIVValueLength());
+ str[GetPRIVValueLength()] = 0;
+ std::cout << " Value: " << str << std::endl;
+ std::cout << " Length: " << GetPRIVValueLength() << std::endl;
+ }
+#endif // RTP_SUPPORT_SDESPRIV
+ } while (GotoNextItem());
+ }
+ } while (GotoNextChunk());
+}
+#endif // RTPDEBUG
+
diff --git a/src/rtcpsdespacket.h b/src/rtcpsdespacket.h
new file mode 100644
index 0000000..8b68a59
--- /dev/null
+++ b/src/rtcpsdespacket.h
@@ -0,0 +1,381 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtcpsdespacket.h
+ */
+
+#ifndef RTCPSDESPACKET_H
+
+#define RTCPSDESPACKET_H
+
+#include "rtpconfig.h"
+#include "rtcppacket.h"
+#include "rtpstructs.h"
+#include "rtpdefines.h"
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ #include <netinet/in.h>
+#endif // WIN32
+
+class RTCPCompoundPacket;
+
+/** Describes an RTCP source description packet. */
+class RTCPSDESPacket : public RTCPPacket
+{
+public:
+ /** Identifies the type of an SDES item. */
+ enum ItemType
+ {
+ None, /**< Used when the iteration over the items has finished. */
+ CNAME, /**< Used for a CNAME (canonical name) item. */
+ NAME, /**< Used for a NAME item. */
+ EMAIL, /**< Used for an EMAIL item. */
+ PHONE, /**< Used for a PHONE item. */
+ LOC, /**< Used for a LOC (location) item. */
+ TOOL, /**< Used for a TOOL item. */
+ NOTE, /**< Used for a NOTE item. */
+ PRIV, /**< Used for a PRIV item. */
+ Unknown /**< Used when there is an item present, but the type is not recognized. */
+ };
+
+ /** Creates an instance based on the data in \c data with length \c datalen.
+ * Creates an instance based on the data in \c data with length \c datalen. Since the \c data pointer
+ * is referenced inside the class (no copy of the data is made) one must make sure that the memory it
+ * points to is valid as long as the class instance exists.
+ */
+ RTCPSDESPacket(uint8_t *data,size_t datalen);
+ ~RTCPSDESPacket() { }
+
+ /** Returns the number of SDES chunks in the SDES packet.
+ * Returns the number of SDES chunks in the SDES packet. Each chunk has its own SSRC identifier.
+ */
+ int GetChunkCount() const;
+
+ /** Starts the iteration over the chunks.
+ * Starts the iteration. If no SDES chunks are present, the function returns \c false. Otherwise,
+ * it returns \c true and sets the current chunk to be the first chunk.
+ */
+ bool GotoFirstChunk();
+
+ /** Sets the current chunk to the next available chunk.
+ * Sets the current chunk to the next available chunk. If no next chunk is present, this function returns
+ * \c false, otherwise it returns \c true.
+ */
+ bool GotoNextChunk();
+
+ /** Returns the SSRC identifier of the current chunk. */
+ uint32_t GetChunkSSRC() const;
+
+ /** Starts the iteration over the SDES items in the current chunk.
+ * Starts the iteration over the SDES items in the current chunk. If no SDES items are
+ * present, the function returns \c false. Otherwise, the function sets the current item
+ * to be the first one and returns \c true.
+ */
+ bool GotoFirstItem();
+
+ /** Advances the iteration to the next item in the current chunk.
+ * If there's another item in the chunk, the current item is set to be the next one and the function
+ * returns \c true. Otherwise, the function returns \c false.
+ */
+ bool GotoNextItem();
+
+ /** Returns the SDES item type of the current item in the current chunk. */
+ ItemType GetItemType() const;
+
+ /** Returns the item length of the current item in the current chunk. */
+ size_t GetItemLength() const;
+
+ /** Returns the item data of the current item in the current chunk. */
+ uint8_t *GetItemData();
+
+#ifdef RTP_SUPPORT_SDESPRIV
+ /** If the current item is an SDES PRIV item, this function returns the length of the
+ * prefix string of the private item.
+ */
+ size_t GetPRIVPrefixLength() const;
+
+ /** If the current item is an SDES PRIV item, this function returns actual data of the
+ * prefix string.
+ */
+ uint8_t *GetPRIVPrefixData();
+
+ /** If the current item is an SDES PRIV item, this function returns the length of the
+ * value string of the private item.
+ */
+ size_t GetPRIVValueLength() const;
+
+ /** If the current item is an SDES PRIV item, this function returns actual value data of the
+ * private item.
+ */
+ uint8_t *GetPRIVValueData();
+#endif // RTP_SUPPORT_SDESPRIV
+
+#ifdef RTPDEBUG
+ void Dump();
+#endif // RTPDEBUG
+private:
+ uint8_t *currentchunk;
+ int curchunknum;
+ size_t itemoffset;
+};
+
+inline int RTCPSDESPacket::GetChunkCount() const
+{
+ if (!knownformat)
+ return 0;
+ RTCPCommonHeader *hdr = (RTCPCommonHeader *)data;
+ return ((int)hdr->count);
+}
+
+inline bool RTCPSDESPacket::GotoFirstChunk()
+{
+ if (GetChunkCount() == 0)
+ {
+ currentchunk = 0;
+ return false;
+ }
+ currentchunk = data+sizeof(RTCPCommonHeader);
+ curchunknum = 1;
+ itemoffset = sizeof(uint32_t);
+ return true;
+}
+
+inline bool RTCPSDESPacket::GotoNextChunk()
+{
+ if (!knownformat)
+ return false;
+ if (currentchunk == 0)
+ return false;
+ if (curchunknum == GetChunkCount())
+ return false;
+
+ size_t offset = sizeof(uint32_t);
+ RTCPSDESHeader *sdeshdr = (RTCPSDESHeader *)(currentchunk+sizeof(uint32_t));
+
+ while (sdeshdr->sdesid != 0)
+ {
+ offset += sizeof(RTCPSDESHeader);
+ offset += (size_t)(sdeshdr->length);
+ sdeshdr = (RTCPSDESHeader *)(currentchunk+offset);
+ }
+ offset++; // for the zero byte
+ if ((offset&0x03) != 0)
+ offset += (4-(offset&0x03));
+ currentchunk += offset;
+ curchunknum++;
+ itemoffset = sizeof(uint32_t);
+ return true;
+}
+
+inline uint32_t RTCPSDESPacket::GetChunkSSRC() const
+{
+ if (!knownformat)
+ return 0;
+ if (currentchunk == 0)
+ return 0;
+ uint32_t *ssrc = (uint32_t *)currentchunk;
+ return ntohl(*ssrc);
+}
+
+inline bool RTCPSDESPacket::GotoFirstItem()
+{
+ if (!knownformat)
+ return false;
+ if (currentchunk == 0)
+ return false;
+ itemoffset = sizeof(uint32_t);
+ RTCPSDESHeader *sdeshdr = (RTCPSDESHeader *)(currentchunk+itemoffset);
+ if (sdeshdr->sdesid == 0)
+ return false;
+ return true;
+}
+
+inline bool RTCPSDESPacket::GotoNextItem()
+{
+ if (!knownformat)
+ return false;
+ if (currentchunk == 0)
+ return false;
+
+ RTCPSDESHeader *sdeshdr = (RTCPSDESHeader *)(currentchunk+itemoffset);
+ if (sdeshdr->sdesid == 0)
+ return false;
+
+ size_t offset = itemoffset;
+ offset += sizeof(RTCPSDESHeader);
+ offset += (size_t)(sdeshdr->length);
+ sdeshdr = (RTCPSDESHeader *)(currentchunk+offset);
+ if (sdeshdr->sdesid == 0)
+ return false;
+ itemoffset = offset;
+ return true;
+}
+
+inline RTCPSDESPacket::ItemType RTCPSDESPacket::GetItemType() const
+{
+ if (!knownformat)
+ return None;
+ if (currentchunk == 0)
+ return None;
+ RTCPSDESHeader *sdeshdr = (RTCPSDESHeader *)(currentchunk+itemoffset);
+ switch (sdeshdr->sdesid)
+ {
+ case 0:
+ return None;
+ case RTCP_SDES_ID_CNAME:
+ return CNAME;
+ case RTCP_SDES_ID_NAME:
+ return NAME;
+ case RTCP_SDES_ID_EMAIL:
+ return EMAIL;
+ case RTCP_SDES_ID_PHONE:
+ return PHONE;
+ case RTCP_SDES_ID_LOCATION:
+ return LOC;
+ case RTCP_SDES_ID_TOOL:
+ return TOOL;
+ case RTCP_SDES_ID_NOTE:
+ return NOTE;
+ case RTCP_SDES_ID_PRIVATE:
+ return PRIV;
+ default:
+ return Unknown;
+ }
+ return Unknown;
+}
+
+inline size_t RTCPSDESPacket::GetItemLength() const
+{
+ if (!knownformat)
+ return None;
+ if (currentchunk == 0)
+ return None;
+ RTCPSDESHeader *sdeshdr = (RTCPSDESHeader *)(currentchunk+itemoffset);
+ if (sdeshdr->sdesid == 0)
+ return 0;
+ return (size_t)(sdeshdr->length);
+}
+
+inline uint8_t *RTCPSDESPacket::GetItemData()
+{
+ if (!knownformat)
+ return 0;
+ if (currentchunk == 0)
+ return 0;
+ RTCPSDESHeader *sdeshdr = (RTCPSDESHeader *)(currentchunk+itemoffset);
+ if (sdeshdr->sdesid == 0)
+ return 0;
+ return (currentchunk+itemoffset+sizeof(RTCPSDESHeader));
+}
+
+#ifdef RTP_SUPPORT_SDESPRIV
+inline size_t RTCPSDESPacket::GetPRIVPrefixLength() const
+{
+ if (!knownformat)
+ return 0;
+ if (currentchunk == 0)
+ return 0;
+ RTCPSDESHeader *sdeshdr = (RTCPSDESHeader *)(currentchunk+itemoffset);
+ if (sdeshdr->sdesid != RTCP_SDES_ID_PRIVATE)
+ return 0;
+ if (sdeshdr->length == 0)
+ return 0;
+ uint8_t *preflen = currentchunk+itemoffset+sizeof(RTCPSDESHeader);
+ size_t prefixlength = (size_t)(*preflen);
+ if (prefixlength > (size_t)((sdeshdr->length)-1))
+ return 0;
+ return prefixlength;
+}
+
+inline uint8_t *RTCPSDESPacket::GetPRIVPrefixData()
+{
+ if (!knownformat)
+ return 0;
+ if (currentchunk == 0)
+ return 0;
+ RTCPSDESHeader *sdeshdr = (RTCPSDESHeader *)(currentchunk+itemoffset);
+ if (sdeshdr->sdesid != RTCP_SDES_ID_PRIVATE)
+ return 0;
+ if (sdeshdr->length == 0)
+ return 0;
+ uint8_t *preflen = currentchunk+itemoffset+sizeof(RTCPSDESHeader);
+ size_t prefixlength = (size_t)(*preflen);
+ if (prefixlength > (size_t)((sdeshdr->length)-1))
+ return 0;
+ if (prefixlength == 0)
+ return 0;
+ return (currentchunk+itemoffset+sizeof(RTCPSDESHeader)+1);
+}
+
+inline size_t RTCPSDESPacket::GetPRIVValueLength() const
+{
+ if (!knownformat)
+ return 0;
+ if (currentchunk == 0)
+ return 0;
+ RTCPSDESHeader *sdeshdr = (RTCPSDESHeader *)(currentchunk+itemoffset);
+ if (sdeshdr->sdesid != RTCP_SDES_ID_PRIVATE)
+ return 0;
+ if (sdeshdr->length == 0)
+ return 0;
+ uint8_t *preflen = currentchunk+itemoffset+sizeof(RTCPSDESHeader);
+ size_t prefixlength = (size_t)(*preflen);
+ if (prefixlength > (size_t)((sdeshdr->length)-1))
+ return 0;
+ return ((size_t)(sdeshdr->length))-prefixlength-1;
+}
+
+inline uint8_t *RTCPSDESPacket::GetPRIVValueData()
+{
+ if (!knownformat)
+ return 0;
+ if (currentchunk == 0)
+ return 0;
+ RTCPSDESHeader *sdeshdr = (RTCPSDESHeader *)(currentchunk+itemoffset);
+ if (sdeshdr->sdesid != RTCP_SDES_ID_PRIVATE)
+ return 0;
+ if (sdeshdr->length == 0)
+ return 0;
+ uint8_t *preflen = currentchunk+itemoffset+sizeof(RTCPSDESHeader);
+ size_t prefixlength = (size_t)(*preflen);
+ if (prefixlength > (size_t)((sdeshdr->length)-1))
+ return 0;
+ size_t valuelen = ((size_t)(sdeshdr->length))-prefixlength-1;
+ if (valuelen == 0)
+ return 0;
+ return (currentchunk+itemoffset+sizeof(RTCPSDESHeader)+1+prefixlength);
+}
+
+#endif // RTP_SUPPORT_SDESPRIV
+
+#endif // RTCPSDESPACKET_H
+
diff --git a/src/rtcpsrpacket.cpp b/src/rtcpsrpacket.cpp
new file mode 100644
index 0000000..2ccc395
--- /dev/null
+++ b/src/rtcpsrpacket.cpp
@@ -0,0 +1,101 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtcpsrpacket.h"
+#ifdef RTPDEBUG
+ #include <iostream>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+RTCPSRPacket::RTCPSRPacket(uint8_t *data,size_t datalength)
+ : RTCPPacket(SR,data,datalength)
+{
+ knownformat = false;
+
+ RTCPCommonHeader *hdr;
+ size_t len = datalength;
+ size_t expectedlength;
+
+ hdr = (RTCPCommonHeader *)data;
+ if (hdr->padding)
+ {
+ uint8_t padcount = data[datalength-1];
+ if ((padcount & 0x03) != 0) // not a multiple of four! (see rfc 3550 p 37)
+ return;
+ if (((size_t)padcount) >= len)
+ return;
+ len -= (size_t)padcount;
+ }
+
+ expectedlength = sizeof(RTCPCommonHeader)+sizeof(uint32_t)+sizeof(RTCPSenderReport);
+ expectedlength += sizeof(RTCPReceiverReport)*((int)hdr->count);
+
+ if (expectedlength != len)
+ return;
+
+ knownformat = true;
+}
+
+#ifdef RTPDEBUG
+void RTCPSRPacket::Dump()
+{
+ RTCPPacket::Dump();
+ if (!IsKnownFormat())
+ std::cout << " Unknown format" << std::endl;
+ else
+ {
+ int num = GetReceptionReportCount();
+ int i;
+ RTPNTPTime t = GetNTPTimestamp();
+
+ std::cout << " SSRC of sender: " << GetSenderSSRC() << std::endl;
+ std::cout << " Sender info:" << std::endl;
+ std::cout << " NTP timestamp: " << t.GetMSW() << ":" << t.GetLSW() << std::endl;
+ std::cout << " RTP timestamp: " << GetRTPTimestamp() << std::endl;
+ std::cout << " Packet count: " << GetSenderPacketCount() << std::endl;
+ std::cout << " Octet count: " << GetSenderOctetCount() << std::endl;
+ for (i = 0 ; i < num ; i++)
+ {
+ std::cout << " Report block " << i << std::endl;
+ std::cout << " SSRC: " << GetSSRC(i) << std::endl;
+ std::cout << " Fraction lost: " << (uint32_t)GetFractionLost(i) << std::endl;
+ std::cout << " Packets lost: " << GetLostPacketCount(i) << std::endl;
+ std::cout << " Seq. nr.: " << GetExtendedHighestSequenceNumber(i) << std::endl;
+ std::cout << " Jitter: " << GetJitter(i) << std::endl;
+ std::cout << " LSR: " << GetLSR(i) << std::endl;
+ std::cout << " DLSR: " << GetDLSR(i) << std::endl;
+ }
+ }
+}
+#endif // RTPDEBUG
+
diff --git a/src/rtcpsrpacket.h b/src/rtcpsrpacket.h
new file mode 100644
index 0000000..03a8442
--- /dev/null
+++ b/src/rtcpsrpacket.h
@@ -0,0 +1,247 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtcpsrpacket.h
+ */
+
+#ifndef RTCPSRPACKET_H
+
+#define RTCPSRPACKET_H
+
+#include "rtpconfig.h"
+#include "rtcppacket.h"
+#include "rtptimeutilities.h"
+#include "rtpstructs.h"
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ #include <netinet/in.h>
+#endif // WIN32
+
+class RTCPCompoundPacket;
+
+/** Describes an RTCP sender report packet. */
+class RTCPSRPacket : public RTCPPacket
+{
+public:
+ /** Creates an instance based on the data in \c data with length \c datalen.
+ * Creates an instance based on the data in \c data with length \c datalen. Since the \c data pointer
+ * is referenced inside the class (no copy of the data is made) one must make sure that the memory it
+ * points to is valid as long as the class instance exists.
+ */
+ RTCPSRPacket(uint8_t *data,size_t datalength);
+ ~RTCPSRPacket() { }
+
+ /** Returns the SSRC of the participant who sent this packet. */
+ uint32_t GetSenderSSRC() const;
+
+ /** Returns the NTP timestamp contained in the sender report. */
+ RTPNTPTime GetNTPTimestamp() const;
+
+ /** Returns the RTP timestamp contained in the sender report. */
+ uint32_t GetRTPTimestamp() const;
+
+ /** Returns the sender's packet count contained in the sender report. */
+ uint32_t GetSenderPacketCount() const;
+
+ /** Returns the sender's octet count contained in the sender report. */
+ uint32_t GetSenderOctetCount() const;
+
+ /** Returns the number of reception report blocks present in this packet. */
+ int GetReceptionReportCount() const;
+
+ /** Returns the SSRC of the reception report block described by \c index which may have a value
+ * from 0 to GetReceptionReportCount()-1 (note that no check is performed to see if \c index is
+ * valid).
+ */
+ uint32_t GetSSRC(int index) const;
+
+ /** Returns the `fraction lost' field of the reception report described by \c index which may have
+ * a value from 0 to GetReceptionReportCount()-1 (note that no check is performed to see if \c index is
+ * valid).
+ */
+ uint8_t GetFractionLost(int index) const;
+
+ /** Returns the number of lost packets in the reception report block described by \c index which may have
+ * a value from 0 to GetReceptionReportCount()-1 (note that no check is performed to see if \c index is
+ * valid).
+ */
+ int32_t GetLostPacketCount(int index) const;
+
+ /** Returns the extended highest sequence number of the reception report block described by \c index which may have
+ * a value from 0 to GetReceptionReportCount()-1 (note that no check is performed to see if \c index is
+ * valid).
+ */
+ uint32_t GetExtendedHighestSequenceNumber(int index) const;
+
+ /** Returns the jitter field of the reception report block described by \c index which may have
+ * a value from 0 to GetReceptionReportCount()-1 (note that no check is performed to see if \c index is
+ * valid).
+ */
+ uint32_t GetJitter(int index) const;
+
+ /** Returns the LSR field of the reception report block described by \c index which may have
+ * a value from 0 to GetReceptionReportCount()-1 (note that no check is performed to see if \c index is
+ * valid).
+ */
+ uint32_t GetLSR(int index) const;
+
+ /** Returns the DLSR field of the reception report block described by \c index which may have
+ * a value from 0 to GetReceptionReportCount()-1 (note that no check is performed to see if \c index is
+ * valid).
+ */
+ uint32_t GetDLSR(int index) const;
+
+#ifdef RTPDEBUG
+ void Dump();
+#endif // RTPDEBUG
+private:
+ RTCPReceiverReport *GotoReport(int index) const;
+};
+
+inline uint32_t RTCPSRPacket::GetSenderSSRC() const
+{
+ if (!knownformat)
+ return 0;
+
+ uint32_t *ssrcptr = (uint32_t *)(data+sizeof(RTCPCommonHeader));
+ return ntohl(*ssrcptr);
+}
+
+inline RTPNTPTime RTCPSRPacket::GetNTPTimestamp() const
+{
+ if (!knownformat)
+ return RTPNTPTime(0,0);
+
+ RTCPSenderReport *sr = (RTCPSenderReport *)(data+sizeof(RTCPCommonHeader)+sizeof(uint32_t));
+ return RTPNTPTime(ntohl(sr->ntptime_msw),ntohl(sr->ntptime_lsw));
+}
+
+inline uint32_t RTCPSRPacket::GetRTPTimestamp() const
+{
+ if (!knownformat)
+ return 0;
+ RTCPSenderReport *sr = (RTCPSenderReport *)(data+sizeof(RTCPCommonHeader)+sizeof(uint32_t));
+ return ntohl(sr->rtptimestamp);
+}
+
+inline uint32_t RTCPSRPacket::GetSenderPacketCount() const
+{
+ if (!knownformat)
+ return 0;
+ RTCPSenderReport *sr = (RTCPSenderReport *)(data+sizeof(RTCPCommonHeader)+sizeof(uint32_t));
+ return ntohl(sr->packetcount);
+}
+
+inline uint32_t RTCPSRPacket::GetSenderOctetCount() const
+{
+ if (!knownformat)
+ return 0;
+ RTCPSenderReport *sr = (RTCPSenderReport *)(data+sizeof(RTCPCommonHeader)+sizeof(uint32_t));
+ return ntohl(sr->octetcount);
+}
+
+inline int RTCPSRPacket::GetReceptionReportCount() const
+{
+ if (!knownformat)
+ return 0;
+ RTCPCommonHeader *hdr = (RTCPCommonHeader *)data;
+ return ((int)hdr->count);
+}
+
+inline RTCPReceiverReport *RTCPSRPacket::GotoReport(int index) const
+{
+ RTCPReceiverReport *r = (RTCPReceiverReport *)(data+sizeof(RTCPCommonHeader)+sizeof(uint32_t)+sizeof(RTCPSenderReport)+index*sizeof(RTCPReceiverReport));
+ return r;
+}
+
+inline uint32_t RTCPSRPacket::GetSSRC(int index) const
+{
+ if (!knownformat)
+ return 0;
+ RTCPReceiverReport *r = GotoReport(index);
+ return ntohl(r->ssrc);
+}
+
+inline uint8_t RTCPSRPacket::GetFractionLost(int index) const
+{
+ if (!knownformat)
+ return 0;
+ RTCPReceiverReport *r = GotoReport(index);
+ return r->fractionlost;
+}
+
+inline int32_t RTCPSRPacket::GetLostPacketCount(int index) const
+{
+ if (!knownformat)
+ return 0;
+ RTCPReceiverReport *r = GotoReport(index);
+ uint32_t count = ((uint32_t)r->packetslost[2])|(((uint32_t)r->packetslost[1])<<8)|(((uint32_t)r->packetslost[0])<<16);
+ if ((count&0x00800000) != 0) // test for negative number
+ count |= 0xFF000000;
+ int32_t *count2 = (int32_t *)(&count);
+ return (*count2);
+}
+
+inline uint32_t RTCPSRPacket::GetExtendedHighestSequenceNumber(int index) const
+{
+ if (!knownformat)
+ return 0;
+ RTCPReceiverReport *r = GotoReport(index);
+ return ntohl(r->exthighseqnr);
+}
+
+inline uint32_t RTCPSRPacket::GetJitter(int index) const
+{
+ if (!knownformat)
+ return 0;
+ RTCPReceiverReport *r = GotoReport(index);
+ return ntohl(r->jitter);
+}
+
+inline uint32_t RTCPSRPacket::GetLSR(int index) const
+{
+ if (!knownformat)
+ return 0;
+ RTCPReceiverReport *r = GotoReport(index);
+ return ntohl(r->lsr);
+}
+
+inline uint32_t RTCPSRPacket::GetDLSR(int index) const
+{
+ if (!knownformat)
+ return 0;
+ RTCPReceiverReport *r = GotoReport(index);
+ return ntohl(r->dlsr);
+}
+
+#endif // RTCPSRPACKET_H
+
diff --git a/src/rtcpunknownpacket.h b/src/rtcpunknownpacket.h
new file mode 100644
index 0000000..4745be7
--- /dev/null
+++ b/src/rtcpunknownpacket.h
@@ -0,0 +1,68 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtcpunknownpacket.h
+ */
+
+#ifndef RTCPUNKNOWNPACKET_H
+
+#define RTCPUNKNOWNPACKET_H
+
+#include "rtpconfig.h"
+#include "rtcppacket.h"
+
+class RTCPCompoundPacket;
+
+/** Describes an RTCP packet of unknown type.
+ * Describes an RTCP packet of unknown type. This class doesn't have any extra member functions besides
+ * the ones it inherited. Note that since an unknown packet type doesn't have any format to check
+ * against, the IsKnownFormat function will trivially return \c true.
+ */
+class RTCPUnknownPacket : public RTCPPacket
+{
+public:
+ /** Creates an instance based on the data in \c data with length \c datalen.
+ * Creates an instance based on the data in \c data with length \c datalen. Since the \c data pointer
+ * is referenced inside the class (no copy of the data is made) one must make sure that the memory it
+ * points to is valid as long as the class instance exists.
+ */
+ RTCPUnknownPacket(uint8_t *data,size_t datalen) : RTCPPacket(Unknown,data,datalen)
+ {
+ // Since we don't expect a format, we'll trivially put knownformat = true
+ knownformat = true;
+ }
+ ~RTCPUnknownPacket() { }
+};
+
+#endif // RTCPUNKNOWNPACKET_H
+
diff --git a/src/rtpaddress.h b/src/rtpaddress.h
new file mode 100644
index 0000000..92e29b1
--- /dev/null
+++ b/src/rtpaddress.h
@@ -0,0 +1,93 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpaddress.h
+ */
+
+#ifndef RTPADDRESS_H
+
+#define RTPADDRESS_H
+
+#include "rtpconfig.h"
+#include <string>
+
+class RTPMemoryManager;
+
+/** This class is an abstract class which is used to specify destinations, multicast groups etc. */
+class RTPAddress
+{
+public:
+ /** Identifies the actual implementation being used. */
+ enum AddressType
+ {
+ IPv4Address, /**< Used by the UDP over IPv4 transmitter. */
+ IPv6Address, /**< Used by the UDP over IPv6 transmitter. */
+ UserDefinedAddress /**< Can be useful for a user-defined transmitter. */
+ };
+
+ /** Returns the type of address the actual implementation represents. */
+ AddressType GetAddressType() const { return addresstype; }
+
+ /** Creates a copy of the RTPAddress instance.
+ * Creates a copy of the RTPAddress instance. If \c mgr is not NULL, the
+ * corresponding memory manager will be used to allocate the memory for the address
+ * copy.
+ */
+ virtual RTPAddress *CreateCopy(RTPMemoryManager *mgr) const = 0;
+
+ /** Checks if the address \c addr is the same address as the one this instance represents.
+ * Checks if the address \c addr is the same address as the one this instance represents.
+ * Implementations must be able to handle a NULL argument.
+ */
+ virtual bool IsSameAddress(const RTPAddress *addr) const = 0;
+
+ /** Checks if the address \c addr represents the same host as this instance.
+ * Checks if the address \c addr represents the same host as this instance. Implementations
+ * must be able to handle a NULL argument.
+ */
+ virtual bool IsFromSameHost(const RTPAddress *addr) const = 0;
+
+#ifdef RTPDEBUG
+ virtual std::string GetAddressString() const = 0;
+#endif // RTPDEBUG
+
+ virtual ~RTPAddress() { }
+protected:
+ // only allow subclasses to be created
+ RTPAddress(const AddressType t) : addresstype(t) { }
+private:
+ const AddressType addresstype;
+};
+
+#endif // RTPADDRESS_H
+
diff --git a/src/rtpcollisionlist.cpp b/src/rtpcollisionlist.cpp
new file mode 100644
index 0000000..4338a33
--- /dev/null
+++ b/src/rtpcollisionlist.cpp
@@ -0,0 +1,125 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtpcollisionlist.h"
+#include "rtperrors.h"
+#include "rtpmemorymanager.h"
+#ifdef RTPDEBUG
+ #include <iostream>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+RTPCollisionList::RTPCollisionList(RTPMemoryManager *mgr) : RTPMemoryObject(mgr)
+{
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ timeinit.Dummy();
+#endif // WIN32 || _WIN32_WCE
+}
+
+void RTPCollisionList::Clear()
+{
+ std::list<AddressAndTime>::iterator it;
+
+ for (it = addresslist.begin() ; it != addresslist.end() ; it++)
+ RTPDelete((*it).addr,GetMemoryManager());
+ addresslist.clear();
+}
+
+int RTPCollisionList::UpdateAddress(const RTPAddress *addr,const RTPTime &receivetime,bool *created)
+{
+ if (addr == 0)
+ return ERR_RTP_COLLISIONLIST_BADADDRESS;
+
+ std::list<AddressAndTime>::iterator it;
+
+ for (it = addresslist.begin() ; it != addresslist.end() ; it++)
+ {
+ if (((*it).addr)->IsSameAddress(addr))
+ {
+ (*it).recvtime = receivetime;
+ *created = false;
+ return 0;
+ }
+ }
+
+ RTPAddress *newaddr = addr->CreateCopy(GetMemoryManager());
+ if (newaddr == 0)
+ return ERR_RTP_OUTOFMEM;
+
+ addresslist.push_back(AddressAndTime(newaddr,receivetime));
+ *created = true;
+ return 0;
+}
+
+bool RTPCollisionList::HasAddress(const RTPAddress *addr) const
+{
+ std::list<AddressAndTime>::const_iterator it;
+
+ for (it = addresslist.begin() ; it != addresslist.end() ; it++)
+ {
+ if (((*it).addr)->IsSameAddress(addr))
+ return true;
+ }
+
+ return false;
+}
+
+void RTPCollisionList::Timeout(const RTPTime &currenttime,const RTPTime &timeoutdelay)
+{
+ std::list<AddressAndTime>::iterator it;
+ RTPTime checktime = currenttime;
+ checktime -= timeoutdelay;
+
+ it = addresslist.begin();
+ while(it != addresslist.end())
+ {
+ if ((*it).recvtime < checktime) // timeout
+ {
+ RTPDelete((*it).addr,GetMemoryManager());
+ it = addresslist.erase(it);
+ }
+ else
+ it++;
+ }
+}
+
+#ifdef RTPDEBUG
+void RTPCollisionList::Dump()
+{
+ std::list<AddressAndTime>::const_iterator it;
+
+ for (it = addresslist.begin() ; it != addresslist.end() ; it++)
+ std::cout << "Address: " << ((*it).addr)->GetAddressString() << "\tTime: " << (*it).recvtime.GetSeconds() << std::endl;
+}
+#endif // RTPDEBUG
+
diff --git a/src/rtpcollisionlist.h b/src/rtpcollisionlist.h
new file mode 100644
index 0000000..c710c42
--- /dev/null
+++ b/src/rtpcollisionlist.h
@@ -0,0 +1,90 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpcollisionlist.h
+ */
+
+#ifndef RTPCOLLISIONLIST_H
+
+#define RTPCOLLISIONLIST_H
+
+#include "rtpconfig.h"
+#include "rtpaddress.h"
+#include "rtptimeutilities.h"
+#include "rtpmemoryobject.h"
+#include <list>
+
+class RTPAddress;
+
+/** This class represents a list of addresses from which SSRC collisions were detected. */
+class RTPCollisionList : public RTPMemoryObject
+{
+public:
+ /** Constructs an instance, optionally installing a memory manager. */
+ RTPCollisionList(RTPMemoryManager *mgr = 0);
+ ~RTPCollisionList() { Clear(); }
+
+ /** Clears the list of addresses. */
+ void Clear();
+
+ /** Updates the entry for address \c addr to indicate that a collision was detected at time \c receivetime.
+ * Updates the entry for address \c addr to indicate that a collision was detected at time \c receivetime.
+ * If the entry did not exist yet, the flag \c created is set to \c true, otherwise it is set to \c false.
+ */
+ int UpdateAddress(const RTPAddress *addr,const RTPTime &receivetime,bool *created);
+
+ /** Returns \c true} if the address \c addr appears in the list. */
+ bool HasAddress(const RTPAddress *addr) const;
+
+ /** Assuming that the current time is given by \c currenttime, this function times out entries which
+ * haven't been updated in the previous time interval specified by \c timeoutdelay.
+ */
+ void Timeout(const RTPTime &currenttime,const RTPTime &timeoutdelay);
+#ifdef RTPDEBUG
+ void Dump();
+#endif // RTPDEBUG
+private:
+ class AddressAndTime
+ {
+ public:
+ AddressAndTime(RTPAddress *a,const RTPTime &t) : addr(a),recvtime(t) { }
+
+ RTPAddress *addr;
+ RTPTime recvtime;
+ };
+
+ std::list<AddressAndTime> addresslist;
+};
+
+#endif // RTPCOLLISIONLIST_H
+
diff --git a/src/rtpconfig.h b/src/rtpconfig.h
new file mode 100644
index 0000000..23539b8
--- /dev/null
+++ b/src/rtpconfig.h
@@ -0,0 +1,45 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#ifndef RTPCONFIG_H
+
+#define RTPCONFIG_H
+
+#if (defined(WIN32) || defined(_WIN32_WCE))
+#include "rtpconfig_win.h"
+#else
+#include "rtpconfig_unix.h"
+#endif // WIN32
+
+//#define RTPDEBUG
+
+#endif // RTPCONFIG_H
diff --git a/src/rtpconfig_unix.h.in b/src/rtpconfig_unix.h.in
new file mode 100644
index 0000000..b4f17bd
--- /dev/null
+++ b/src/rtpconfig_unix.h.in
@@ -0,0 +1,72 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#ifndef RTPCONFIG_UNIX_H
+
+#define RTPCONFIG_UNIX_H
+
+@RTP_FILIO@
+
+@RTP_SOCKIO@
+
+@RTP_ENDIAN@
+
+@RTP_SOCKLENTYPE_UINT@
+
+@RTP_HAVE_SOCKADDR_LEN@
+
+@RTP_SUPPORT_IPV4MULTICAST@
+
+@RTP_SUPPORT_THREAD@
+
+@RTP_SUPPORT_SDESPRIV@
+
+@RTP_SUPPORT_PROBATION@
+
+@RTP_SUPPORT_GNUDRAND@
+
+@RTP_SUPPORT_RANDR@
+
+@RTP_SUPPORT_GETLOGINR@
+
+@RTP_SUPPORT_IPV6@
+
+@RTP_SUPPORT_IPV6MULTICAST@
+
+@RTP_SUPPORT_IFADDRS@
+
+@RTP_SUPPORT_SENDAPP@
+
+@RTP_SUPPORT_MEMORYMANAGEMENT@
+
+#endif // RTPCONFIG_UNIX_H
+
diff --git a/src/rtpconfig_win.h b/src/rtpconfig_win.h
new file mode 100644
index 0000000..f5bfc0d
--- /dev/null
+++ b/src/rtpconfig_win.h
@@ -0,0 +1,54 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#ifndef RTPCONFIG_WIN_H
+
+#define RTPCONFIG_WIN_H
+
+#define RTP_SUPPORT_IPV4MULTICAST
+
+#define RTP_SUPPORT_THREAD
+
+#define RTP_SUPPORT_PROBATION
+
+#define RTP_SUPPORT_SDESPRIV
+
+//#define RTP_SUPPORT_IPV6
+
+//#define RTP_SUPPORT_IPV6MULTICAST
+
+#define RTP_SUPPORT_SENDAPP
+
+#define RTP_SUPPORT_MEMORYMANAGEMENT
+
+#endif // RTPCONFIG_WIN_H
+
diff --git a/src/rtpdebug.cpp b/src/rtpdebug.cpp
new file mode 100644
index 0000000..e8d0f6f
--- /dev/null
+++ b/src/rtpdebug.cpp
@@ -0,0 +1,178 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtpconfig.h"
+
+#ifdef RTPDEBUG
+
+#include "rtptypes.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+struct MemoryInfo
+{
+ void *ptr;
+ size_t size;
+ int lineno;
+ char *filename;
+
+ MemoryInfo *next;
+};
+
+class MemoryTracker
+{
+public:
+ MemoryTracker() { firstblock = NULL; }
+ ~MemoryTracker()
+ {
+ MemoryInfo *tmp;
+ int count = 0;
+
+ printf("Checking for memory leaks...\n");fflush(stdout);
+ while(firstblock)
+ {
+ count++;
+ printf("Unfreed block %p of %d bytes (file '%s', line %d)\n",firstblock->ptr,(int)firstblock->size,firstblock->filename,firstblock->lineno);;
+
+ tmp = firstblock->next;
+
+ free(firstblock->ptr);
+ if (firstblock->filename)
+ free(firstblock->filename);
+ free(firstblock);
+ firstblock = tmp;
+ }
+ if (count == 0)
+ printf("No memory leaks found\n");
+ else
+ printf("%d leaks found\n",count);
+ }
+
+ MemoryInfo *firstblock;
+};
+
+static MemoryTracker memtrack;
+
+void *donew(size_t s,char filename[],int line)
+{
+ void *p;
+ MemoryInfo *meminf;
+
+ p = malloc(s);
+ meminf = (MemoryInfo *)malloc(sizeof(MemoryInfo));
+
+ meminf->ptr = p;
+ meminf->size = s;
+ meminf->lineno = line;
+ meminf->filename = (char *)malloc(strlen(filename)+1);
+ strcpy(meminf->filename,filename);
+ meminf->next = memtrack.firstblock;
+
+ memtrack.firstblock = meminf;
+
+ return p;
+}
+
+void dodelete(void *p)
+{
+ MemoryInfo *tmp,*tmpprev;
+ bool found;
+
+ tmpprev = NULL;
+ tmp = memtrack.firstblock;
+ found = false;
+ while (tmp != NULL && !found)
+ {
+ if (tmp->ptr == p)
+ found = true;
+ else
+ {
+ tmpprev = tmp;
+ tmp = tmp->next;
+ }
+ }
+ if (!found)
+ {
+ printf("Couldn't free block %p!\n",p);
+ fflush(stdout);
+ }
+ else
+ {
+ MemoryInfo *n;
+
+ fflush(stdout);
+ n = tmp->next;
+ free(tmp->ptr);
+ if (tmp->filename)
+ free(tmp->filename);
+ free(tmp);
+
+ if (tmpprev)
+ tmpprev->next = n;
+ else
+ memtrack.firstblock = n;
+ }
+}
+
+void *operator new(size_t s)
+{
+ return donew(s,"UNKNOWN FILE",0);
+}
+
+void *operator new[](size_t s)
+{
+ return donew(s,"UNKNOWN FILE",0);
+}
+
+void *operator new(size_t s,char filename[],int line)
+{
+ return donew(s,filename,line);
+}
+
+void *operator new[](size_t s,char filename[],int line)
+{
+ return donew(s,filename,line);
+}
+
+void operator delete(void *p)
+{
+ dodelete(p);
+}
+
+void operator delete[](void *p)
+{
+ dodelete(p);
+}
+
+#endif // RTPDEBUG
+
diff --git a/src/rtpdebug.h b/src/rtpdebug.h
new file mode 100644
index 0000000..d15bd85
--- /dev/null
+++ b/src/rtpdebug.h
@@ -0,0 +1,52 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#ifndef RTPDEBUG_H
+
+#define RTPDEBUG_H
+
+#include "rtpconfig.h"
+
+#ifdef RTPDEBUG
+ #include "rtptypes.h"
+
+ void *operator new(size_t s,char filename[],int line);
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ void *operator new[](size_t s,char filename[],int line);
+ #define new new (__FILE__,__LINE__)
+#else
+ #define new new (__FILE__,__LINE__)
+#endif // WIN32
+#endif // RTPDEBUG
+
+#endif // RTPDEBUG_H
+
diff --git a/src/rtpdefines.h b/src/rtpdefines.h
new file mode 100644
index 0000000..85eb9d1
--- /dev/null
+++ b/src/rtpdefines.h
@@ -0,0 +1,86 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#ifndef RTPDEFINES_H
+
+#define RTPDEFINES_H
+
+#define RTP_VERSION 2
+#define RTP_MAXCSRCS 15
+#define RTP_MINPACKETSIZE 600
+#define RTP_DEFAULTPACKETSIZE 1400
+#define RTP_PROBATIONCOUNT 2
+#define RTP_MAXPRIVITEMS 256
+#define RTP_SENDERTIMEOUTMULTIPLIER 2
+#define RTP_BYETIMEOUTMULTIPLIER 1
+#define RTP_MEMBERTIMEOUTMULTIPLIER 5
+#define RTP_COLLISIONTIMEOUTMULTIPLIER 10
+#define RTP_NOTETTIMEOUTMULTIPLIER 25
+#define RTP_DEFAULTSESSIONBANDWIDTH 10000.0
+
+#define RTP_RTCPTYPE_SR 200
+#define RTP_RTCPTYPE_RR 201
+#define RTP_RTCPTYPE_SDES 202
+#define RTP_RTCPTYPE_BYE 203
+#define RTP_RTCPTYPE_APP 204
+
+#define RTCP_SDES_ID_CNAME 1
+#define RTCP_SDES_ID_NAME 2
+#define RTCP_SDES_ID_EMAIL 3
+#define RTCP_SDES_ID_PHONE 4
+#define RTCP_SDES_ID_LOCATION 5
+#define RTCP_SDES_ID_TOOL 6
+#define RTCP_SDES_ID_NOTE 7
+#define RTCP_SDES_ID_PRIVATE 8
+#define RTCP_SDES_NUMITEMS_NONPRIVATE 7
+#define RTCP_SDES_MAXITEMLENGTH 255
+
+#define RTCP_BYE_MAXREASONLENGTH 255
+#define RTCP_DEFAULTMININTERVAL 5.0
+#define RTCP_DEFAULTBANDWIDTHFRACTION 0.05
+#define RTCP_DEFAULTSENDERFRACTION 0.25
+#define RTCP_DEFAULTHALFATSTARTUP true
+#define RTCP_DEFAULTIMMEDIATEBYE true
+#define RTCP_DEFAULTSRBYE true
+
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ #if (!defined(_WIN32_WCE)) && (defined(_MSC_VER) && _MSC_VER >= 1400 )
+ #define RTP_SNPRINTF _snprintf_s
+ #else
+ #define RTP_SNPRINTF _snprintf
+ #endif
+#else
+ #define RTP_SNPRINTF snprintf
+#endif // WIN32 || _WIN32_WCE
+
+#endif // RTPDEFINES_H
+
diff --git a/src/rtperrors.cpp b/src/rtperrors.cpp
new file mode 100644
index 0000000..a6a16c9
--- /dev/null
+++ b/src/rtperrors.cpp
@@ -0,0 +1,229 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtperrors.h"
+#include "rtpdefines.h"
+
+#include "rtpdebug.h"
+
+struct RTPErrorInfo
+{
+ int code;
+ char *description;
+};
+
+static RTPErrorInfo ErrorDescriptions[]=
+{
+ { ERR_RTP_OUTOFMEM,"Out of memory" },
+ { ERR_RTP_NOTHREADSUPPORT, "No JThread support was compiled in"},
+ { ERR_RTP_COLLISIONLIST_BADADDRESS, "Passed invalid address (null) to collision list"},
+ { ERR_RTP_HASHTABLE_ELEMENTALREADYEXISTS, "Element already exists in hash table"},
+ { ERR_RTP_HASHTABLE_ELEMENTNOTFOUND, "Element not found in hash table"},
+ { ERR_RTP_HASHTABLE_FUNCTIONRETURNEDINVALIDHASHINDEX, "Function returned an illegal hash index"},
+ { ERR_RTP_HASHTABLE_NOCURRENTELEMENT, "No current element selected in hash table"},
+ { ERR_RTP_KEYHASHTABLE_FUNCTIONRETURNEDINVALIDHASHINDEX, "Function returned an illegal hash index"},
+ { ERR_RTP_KEYHASHTABLE_KEYALREADYEXISTS, "Key value already exists in key hash table"},
+ { ERR_RTP_KEYHASHTABLE_KEYNOTFOUND, "Key value not found in key hash table"},
+ { ERR_RTP_KEYHASHTABLE_NOCURRENTELEMENT, "No current element selected in key hash table"},
+ { ERR_RTP_PACKBUILD_ALREADYINIT, "RTP packet builder is already initialized"},
+ { ERR_RTP_PACKBUILD_CSRCALREADYINLIST, "The specified CSRC is already in the RTP packet builder's CSRC list"},
+ { ERR_RTP_PACKBUILD_CSRCLISTFULL, "The RTP packet builder's CSRC list already contains 15 entries"},
+ { ERR_RTP_PACKBUILD_CSRCNOTINLIST, "The specified CSRC was not found in the RTP packet builder's CSRC list"},
+ { ERR_RTP_PACKBUILD_DEFAULTMARKNOTSET, "The RTP packet builder's default mark flag is not set"},
+ { ERR_RTP_PACKBUILD_DEFAULTPAYLOADTYPENOTSET, "The RTP packet builder's default payload type is not set"},
+ { ERR_RTP_PACKBUILD_DEFAULTTSINCNOTSET, "The RTP packet builder's default timestamp increment is not set"},
+ { ERR_RTP_PACKBUILD_INVALIDMAXPACKETSIZE, "The specified maximum packet size for the RTP packet builder is invalid"},
+ { ERR_RTP_PACKBUILD_NOTINIT, "The RTP packet builder is not initialized"},
+ { ERR_RTP_PACKET_BADPAYLOADTYPE, "Invalid payload type"},
+ { ERR_RTP_PACKET_DATAEXCEEDSMAXSIZE, "Tried to create an RTP packet which whould exceed the specified maximum packet size"},
+ { ERR_RTP_PACKET_EXTERNALBUFFERNULL, "Illegal value (null) passed as external buffer for the RTP packet"},
+ { ERR_RTP_PACKET_ILLEGALBUFFERSIZE, "Illegal buffer size specified for the RTP packet"},
+ { ERR_RTP_PACKET_INVALIDPACKET, "Invalid RTP packet format"},
+ { ERR_RTP_PACKET_TOOMANYCSRCS, "More than 15 CSRCs specified for the RTP packet"},
+ { ERR_RTP_POLLTHREAD_ALREADYRUNNING, "Poll thread is already running"},
+ { ERR_RTP_POLLTHREAD_CANTINITMUTEX, "Can't initialize a mutex for the poll thread"},
+ { ERR_RTP_POLLTHREAD_CANTSTARTTHREAD, "Can't start the poll thread"},
+ { ERR_RTP_RTCPCOMPOUND_INVALIDPACKET, "Invalid RTCP compound packet format"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYBUILDING, "Already building this RTCP compound packet"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYBUILT, "This RTCP compound packet is already built"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYGOTREPORT, "There's already a SR or RR in this RTCP compound packet"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_APPDATALENTOOBIG, "The specified APP data length for the RTCP compound packet is too big"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_BUFFERSIZETOOSMALL, "The specified buffer size for the RTCP comound packet is too small"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_ILLEGALAPPDATALENGTH, "The APP data length must be a multiple of four"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_ILLEGALSUBTYPE, "The APP packet subtype must be smaller than 32"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_INVALIDITEMTYPE, "Invalid SDES item type specified for the RTCP compound packet"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_MAXPACKETSIZETOOSMALL, "The specified maximum packet size for the RTCP compound packet is too small"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_NOCURRENTSOURCE, "Tried to add an SDES item to the RTCP compound packet when no SSRC was present"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_NOREPORTPRESENT, "An RTCP compound packet must contain a SR or RR"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING, "The RTCP compound packet builder is not initialized"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT, "Adding this data would exceed the specified maximum RTCP compound packet size"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_REPORTNOTSTARTED, "Tried to add a report block to the RTCP compound packet when no SR or RR was started"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_TOOMANYSSRCS, "Only 31 SSRCs will fit into a BYE packet for the RTCP compound packet"},
+ { ERR_RTP_RTCPCOMPPACKBUILDER_TOTALITEMLENGTHTOOBIG, "The total data for the SDES PRIV item exceeds the maximum size (255 bytes) of an SDES item"},
+ { ERR_RTP_RTCPPACKETBUILDER_ALREADYINIT, "The RTCP packet builder is already initialized"},
+ { ERR_RTP_RTCPPACKETBUILDER_ILLEGALMAXPACKSIZE, "The specified maximum packet size for the RTCP packet builder is too small"},
+ { ERR_RTP_RTCPPACKETBUILDER_ILLEGALTIMESTAMPUNIT, "Speficied an illegal timestamp unit for the the RTCP packet builder"},
+ { ERR_RTP_RTCPPACKETBUILDER_NOTINIT, "The RTCP packet builder was not initialized"},
+ { ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON, "The RTCP compound packet filled sooner than expected"},
+ { ERR_RTP_SCHEDPARAMS_BADFRACTION, "Illegal sender bandwidth fraction specified"},
+ { ERR_RTP_SCHEDPARAMS_BADMINIMUMINTERVAL, "The minimum RTCP interval specified for the scheduler is too small"},
+ { ERR_RTP_SCHEDPARAMS_INVALIDBANDWIDTH, "Invalid RTCP bandwidth specified for the RTCP scheduler"},
+ { ERR_RTP_SDES_LENGTHTOOBIG, "Specified size for the SDES item exceeds 255 bytes"},
+ { ERR_RTP_SDES_PREFIXNOTFOUND, "The specified SDES PRIV prefix was not found"},
+ { ERR_RTP_SESSION_ALREADYCREATED, "The session is already created"},
+ { ERR_RTP_SESSION_CANTGETLOGINNAME, "Can't retrieve login name"},
+ { ERR_RTP_SESSION_CANTINITMUTEX, "A mutex for the RTP session couldn't be initialized"},
+ { ERR_RTP_SESSION_MAXPACKETSIZETOOSMALL, "The maximum packet size specified for the RTP session is too small"},
+ { ERR_RTP_SESSION_NOTCREATED, "The RTP session was not created"},
+ { ERR_RTP_SESSION_UNSUPPORTEDTRANSMISSIONPROTOCOL, "The requested transmission protocol for the RTP session is not supported"},
+ { ERR_RTP_SESSION_USINGPOLLTHREAD, "This function is not available when using the RTP poll thread feature"},
+ { ERR_RTP_SESSION_USERDEFINEDTRANSMITTERNULL, "A user-defined transmitter was requested but the supplied transmitter component is NULL"},
+ { ERR_RTP_SOURCES_ALREADYHAVEOWNSSRC, "Only one source can be marked as own SSRC in the source table"},
+ { ERR_RTP_SOURCES_DONTHAVEOWNSSRC, "No source was marked as own SSRC in the source table"},
+ { ERR_RTP_SOURCES_ILLEGALSDESTYPE, "Illegal SDES type specified for processing into the source table"},
+ { ERR_RTP_SOURCES_SSRCEXISTS, "Can't create own SSRC because this SSRC identifier is already in the source table"},
+ { ERR_RTP_UDPV4TRANS_ALREADYCREATED, "The transmitter was already created"},
+ { ERR_RTP_UDPV4TRANS_ALREADYINIT, "The transmitter was already initialize"},
+ { ERR_RTP_UDPV4TRANS_ALREADYWAITING, "The transmitter is already waiting for incoming data"},
+ { ERR_RTP_UDPV4TRANS_CANTBINDRTCPSOCKET, "The 'bind' call for the RTCP socket failed"},
+ { ERR_RTP_UDPV4TRANS_CANTBINDRTPSOCKET, "The 'bind' call for the RTP socket failed"},
+ { ERR_RTP_UDPV4TRANS_CANTCALCULATELOCALIP, "The local IP addresses could not be determined"},
+ { ERR_RTP_UDPV4TRANS_CANTCREATEABORTDESCRIPTORS, "Couldn't create the sockets used to abort waiting for incoming data"},
+ { ERR_RTP_UDPV4TRANS_CANTCREATEPIPE, "Couldn't create the pipe used to abort waiting for incoming data"},
+ { ERR_RTP_UDPV4TRANS_CANTCREATESOCKET, "Couldn't create the RTP or RTCP socket"},
+ { ERR_RTP_UDPV4TRANS_CANTINITMUTEX, "Failed to initialize a mutex used by the transmitter"},
+ { ERR_RTP_UDPV4TRANS_CANTSETRTCPRECEIVEBUF, "Couldn't set the receive buffer size for the RTCP socket"},
+ { ERR_RTP_UDPV4TRANS_CANTSETRTCPTRANSMITBUF, "Couldn't set the transmission buffer size for the RTCP socket"},
+ { ERR_RTP_UDPV4TRANS_CANTSETRTPRECEIVEBUF, "Couldn't set the receive buffer size for the RTP socket"},
+ { ERR_RTP_UDPV4TRANS_CANTSETRTPTRANSMITBUF, "Couldn't set the transmission buffer size for the RTP socket"},
+ { ERR_RTP_UDPV4TRANS_COULDNTJOINMULTICASTGROUP, "Unable to join the specified multicast group"},
+ { ERR_RTP_UDPV4TRANS_DIFFERENTRECEIVEMODE, "The function called doens't match the current receive mode"},
+ { ERR_RTP_UDPV4TRANS_ERRORINSELECT, "Error in the transmitter's 'select' call"},
+ { ERR_RTP_UDPV4TRANS_ILLEGALPARAMETERS, "Illegal parameters type passed to the transmitter"},
+ { ERR_RTP_UDPV4TRANS_INVALIDADDRESSTYPE, "Specified address type isn't compatible with this transmitter"},
+ { ERR_RTP_UDPV4TRANS_NOLOCALIPS, "Couldn't determine the local host name since the local IP list is empty"},
+ { ERR_RTP_UDPV4TRANS_NOMULTICASTSUPPORT, "Multicast support is not available"},
+ { ERR_RTP_UDPV4TRANS_NOSUCHENTRY, "Specified entry could not be found"},
+ { ERR_RTP_UDPV4TRANS_NOTAMULTICASTADDRESS, "The specified address is not a multicast address"},
+ { ERR_RTP_UDPV4TRANS_NOTCREATED, "The 'Create' call for this transmitter has not been called"},
+ { ERR_RTP_UDPV4TRANS_NOTINIT, "The 'Init' call for this transmitter has not been called"},
+ { ERR_RTP_UDPV4TRANS_NOTWAITING, "The transmitter is not waiting for incoming data"},
+ { ERR_RTP_UDPV4TRANS_PORTBASENOTEVEN, "The specified port base is not an even number"},
+ { ERR_RTP_UDPV4TRANS_SPECIFIEDSIZETOOBIG, "The maximum packet size is too big for this transmitter"},
+ { ERR_RTP_UDPV6TRANS_ALREADYCREATED, "The transmitter was already created"},
+ { ERR_RTP_UDPV6TRANS_ALREADYINIT, "The transmitter was already initialize"},
+ { ERR_RTP_UDPV6TRANS_ALREADYWAITING, "The transmitter is already waiting for incoming data"},
+ { ERR_RTP_UDPV6TRANS_CANTBINDRTCPSOCKET, "The 'bind' call for the RTCP socket failed"},
+ { ERR_RTP_UDPV6TRANS_CANTBINDRTPSOCKET, "The 'bind' call for the RTP socket failed"},
+ { ERR_RTP_UDPV6TRANS_CANTCALCULATELOCALIP, "The local IP addresses could not be determined"},
+ { ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS, "Couldn't create the sockets used to abort waiting for incoming data"},
+ { ERR_RTP_UDPV6TRANS_CANTCREATEPIPE, "Couldn't create the pipe used to abort waiting for incoming data"},
+ { ERR_RTP_UDPV6TRANS_CANTCREATESOCKET, "Couldn't create the RTP or RTCP socket"},
+ { ERR_RTP_UDPV6TRANS_CANTINITMUTEX, "Failed to initialize a mutex used by the transmitter"},
+ { ERR_RTP_UDPV6TRANS_CANTSETRTCPRECEIVEBUF, "Couldn't set the receive buffer size for the RTCP socket"},
+ { ERR_RTP_UDPV6TRANS_CANTSETRTCPTRANSMITBUF, "Couldn't set the transmission buffer size for the RTCP socket"},
+ { ERR_RTP_UDPV6TRANS_CANTSETRTPRECEIVEBUF, "Couldn't set the receive buffer size for the RTP socket"},
+ { ERR_RTP_UDPV6TRANS_CANTSETRTPTRANSMITBUF, "Couldn't set the transmission buffer size for the RTP socket"},
+ { ERR_RTP_UDPV6TRANS_COULDNTJOINMULTICASTGROUP, "Unable to join the specified multicast group"},
+ { ERR_RTP_UDPV6TRANS_DIFFERENTRECEIVEMODE, "The function called doens't match the current receive mode"},
+ { ERR_RTP_UDPV6TRANS_ERRORINSELECT, "Error in the transmitter's 'select' call"},
+ { ERR_RTP_UDPV6TRANS_ILLEGALPARAMETERS, "Illegal parameters type passed to the transmitter"},
+ { ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE, "Specified address type isn't compatible with this transmitter"},
+ { ERR_RTP_UDPV6TRANS_NOLOCALIPS, "Couldn't determine the local host name since the local IP list is empty"},
+ { ERR_RTP_UDPV6TRANS_NOMULTICASTSUPPORT, "Multicast support is not available"},
+ { ERR_RTP_UDPV6TRANS_NOSUCHENTRY, "Specified entry could not be found"},
+ { ERR_RTP_UDPV6TRANS_NOTAMULTICASTADDRESS, "The specified address is not a multicast address"},
+ { ERR_RTP_UDPV6TRANS_NOTCREATED, "The 'Create' call for this transmitter has not been called"},
+ { ERR_RTP_UDPV6TRANS_NOTINIT, "The 'Init' call for this transmitter has not been called"},
+ { ERR_RTP_UDPV6TRANS_NOTWAITING, "The transmitter is not waiting for incoming data"},
+ { ERR_RTP_UDPV6TRANS_PORTBASENOTEVEN, "The specified port base is not an even number"},
+ { ERR_RTP_UDPV6TRANS_SPECIFIEDSIZETOOBIG, "The maximum packet size is too big for this transmitter"},
+ { ERR_RTP_TRANS_BUFFERLENGTHTOOSMALL,"The hostname is larger than the specified buffer size"},
+ { ERR_RTP_SDES_MAXPRIVITEMS,"The maximum number of SDES private item prefixes was reached"},
+ { ERR_RTP_INTERNALSOURCEDATA_INVALIDPROBATIONTYPE,"An invalid probation type was specified"},
+ { ERR_RTP_FAKETRANS_ALREADYCREATED, "The transmitter was already created"},
+ { ERR_RTP_FAKETRANS_ALREADYINIT, "The transmitter was already initialize"},
+ { ERR_RTP_FAKETRANS_ALREADYWAITING, "The transmitter is already waiting for incoming data"},
+ { ERR_RTP_FAKETRANS_CANTBINDRTCPSOCKET, "The 'bind' call for the RTCP socket failed"},
+ { ERR_RTP_FAKETRANS_CANTBINDRTPSOCKET, "The 'bind' call for the RTP socket failed"},
+ { ERR_RTP_FAKETRANS_CANTCALCULATELOCALIP, "The local IP addresses could not be determined"},
+ { ERR_RTP_FAKETRANS_CANTCREATEABORTDESCRIPTORS, "Couldn't create the sockets used to abort waiting for incoming data"},
+ { ERR_RTP_FAKETRANS_CANTCREATEPIPE, "Couldn't create the pipe used to abort waiting for incoming data"},
+ { ERR_RTP_FAKETRANS_CANTCREATESOCKET, "Couldn't create the RTP or RTCP socket"},
+ { ERR_RTP_FAKETRANS_CANTINITMUTEX, "Failed to initialize a mutex used by the transmitter"},
+ { ERR_RTP_FAKETRANS_CANTSETRTCPRECEIVEBUF, "Couldn't set the receive buffer size for the RTCP socket"},
+ { ERR_RTP_FAKETRANS_CANTSETRTCPTRANSMITBUF, "Couldn't set the transmission buffer size for the RTCP socket"},
+ { ERR_RTP_FAKETRANS_CANTSETRTPRECEIVEBUF, "Couldn't set the receive buffer size for the RTP socket"},
+ { ERR_RTP_FAKETRANS_CANTSETRTPTRANSMITBUF, "Couldn't set the transmission buffer size for the RTP socket"},
+ { ERR_RTP_FAKETRANS_COULDNTJOINMULTICASTGROUP, "Unable to join the specified multicast group"},
+ { ERR_RTP_FAKETRANS_DIFFERENTRECEIVEMODE, "The function called doens't match the current receive mode"},
+ { ERR_RTP_FAKETRANS_ERRORINSELECT, "Error in the transmitter's 'select' call"},
+ { ERR_RTP_FAKETRANS_ILLEGALPARAMETERS, "Illegal parameters type passed to the transmitter"},
+ { ERR_RTP_FAKETRANS_INVALIDADDRESSTYPE, "Specified address type isn't compatible with this transmitter"},
+ { ERR_RTP_FAKETRANS_NOLOCALIPS, "Couldn't determine the local host name since the local IP list is empty"},
+ { ERR_RTP_FAKETRANS_NOMULTICASTSUPPORT, "Multicast support is not available"},
+ { ERR_RTP_FAKETRANS_NOSUCHENTRY, "Specified entry could not be found"},
+ { ERR_RTP_FAKETRANS_NOTAMULTICASTADDRESS, "The specified address is not a multicast address"},
+ { ERR_RTP_FAKETRANS_NOTCREATED, "The 'Create' call for this transmitter has not been called"},
+ { ERR_RTP_FAKETRANS_NOTINIT, "The 'Init' call for this transmitter has not been called"},
+ { ERR_RTP_FAKETRANS_NOTWAITING, "The transmitter is not waiting for incoming data"},
+ { ERR_RTP_FAKETRANS_PORTBASENOTEVEN, "The specified port base is not an even number"},
+ { ERR_RTP_FAKETRANS_SPECIFIEDSIZETOOBIG, "The maximum packet size is too big for this transmitter"},
+ { ERR_RTP_FAKETRANS_INVALIDEVENT, "Expecting UNKNOWN_EVENT to set source address but got another type of event"},
+ { ERR_RTP_FAKETRANS_SRCADDRNOTSET, "Got packet but src address information was not set, returning"},
+ { ERR_RTP_FAKETRANS_NOTNETBUFFER, "Received buffer is not a GstNetBuffer"},
+ { ERR_RTP_FAKETRANS_WAITNOTIMPLEMENTED, "The WaitForIncomingData is not implemented in the Gst transmitter"},
+ { 0,0 }
+};
+
+std::string RTPGetErrorString(int errcode)
+{
+ int i;
+
+ if (errcode >= 0)
+ return std::string("No error");
+
+ i = 0;
+ while (ErrorDescriptions[i].code != 0)
+ {
+ if (ErrorDescriptions[i].code == errcode)
+ return std::string(ErrorDescriptions[i].description);
+ i++;
+ }
+
+ char str[16];
+
+ RTP_SNPRINTF(str,16,"(%d)",errcode);
+
+ return std::string("Unknown error code") + std::string(str);
+}
+
diff --git a/src/rtperrors.h b/src/rtperrors.h
new file mode 100644
index 0000000..51a33d7
--- /dev/null
+++ b/src/rtperrors.h
@@ -0,0 +1,209 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtperrors.h
+ */
+
+#ifndef RTPERRORS_H
+
+#define RTPERRORS_H
+
+#include <string>
+
+/** Returns a string describing the error code \c errcode. */
+std::string RTPGetErrorString(int errcode);
+
+#define ERR_RTP_OUTOFMEM -1
+#define ERR_RTP_NOTHREADSUPPORT -2
+#define ERR_RTP_COLLISIONLIST_BADADDRESS -3
+#define ERR_RTP_HASHTABLE_ELEMENTALREADYEXISTS -4
+#define ERR_RTP_HASHTABLE_ELEMENTNOTFOUND -5
+#define ERR_RTP_HASHTABLE_FUNCTIONRETURNEDINVALIDHASHINDEX -6
+#define ERR_RTP_HASHTABLE_NOCURRENTELEMENT -7
+#define ERR_RTP_KEYHASHTABLE_FUNCTIONRETURNEDINVALIDHASHINDEX -8
+#define ERR_RTP_KEYHASHTABLE_KEYALREADYEXISTS -9
+#define ERR_RTP_KEYHASHTABLE_KEYNOTFOUND -10
+#define ERR_RTP_KEYHASHTABLE_NOCURRENTELEMENT -11
+#define ERR_RTP_PACKBUILD_ALREADYINIT -12
+#define ERR_RTP_PACKBUILD_CSRCALREADYINLIST -13
+#define ERR_RTP_PACKBUILD_CSRCLISTFULL -14
+#define ERR_RTP_PACKBUILD_CSRCNOTINLIST -15
+#define ERR_RTP_PACKBUILD_DEFAULTMARKNOTSET -16
+#define ERR_RTP_PACKBUILD_DEFAULTPAYLOADTYPENOTSET -17
+#define ERR_RTP_PACKBUILD_DEFAULTTSINCNOTSET -18
+#define ERR_RTP_PACKBUILD_INVALIDMAXPACKETSIZE -19
+#define ERR_RTP_PACKBUILD_NOTINIT -20
+#define ERR_RTP_PACKET_BADPAYLOADTYPE -21
+#define ERR_RTP_PACKET_DATAEXCEEDSMAXSIZE -22
+#define ERR_RTP_PACKET_EXTERNALBUFFERNULL -23
+#define ERR_RTP_PACKET_ILLEGALBUFFERSIZE -24
+#define ERR_RTP_PACKET_INVALIDPACKET -25
+#define ERR_RTP_PACKET_TOOMANYCSRCS -26
+#define ERR_RTP_POLLTHREAD_ALREADYRUNNING -27
+#define ERR_RTP_POLLTHREAD_CANTINITMUTEX -28
+#define ERR_RTP_POLLTHREAD_CANTSTARTTHREAD -29
+#define ERR_RTP_RTCPCOMPOUND_INVALIDPACKET -30
+#define ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYBUILDING -31
+#define ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYBUILT -32
+#define ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYGOTREPORT -33
+#define ERR_RTP_RTCPCOMPPACKBUILDER_APPDATALENTOOBIG -34
+#define ERR_RTP_RTCPCOMPPACKBUILDER_BUFFERSIZETOOSMALL -35
+#define ERR_RTP_RTCPCOMPPACKBUILDER_ILLEGALAPPDATALENGTH -36
+#define ERR_RTP_RTCPCOMPPACKBUILDER_ILLEGALSUBTYPE -37
+#define ERR_RTP_RTCPCOMPPACKBUILDER_INVALIDITEMTYPE -38
+#define ERR_RTP_RTCPCOMPPACKBUILDER_MAXPACKETSIZETOOSMALL -39
+#define ERR_RTP_RTCPCOMPPACKBUILDER_NOCURRENTSOURCE -40
+#define ERR_RTP_RTCPCOMPPACKBUILDER_NOREPORTPRESENT -41
+#define ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING -42
+#define ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT -43
+#define ERR_RTP_RTCPCOMPPACKBUILDER_REPORTNOTSTARTED -44
+#define ERR_RTP_RTCPCOMPPACKBUILDER_TOOMANYSSRCS -45
+#define ERR_RTP_RTCPCOMPPACKBUILDER_TOTALITEMLENGTHTOOBIG -46
+#define ERR_RTP_RTCPPACKETBUILDER_ALREADYINIT -47
+#define ERR_RTP_RTCPPACKETBUILDER_ILLEGALMAXPACKSIZE -48
+#define ERR_RTP_RTCPPACKETBUILDER_ILLEGALTIMESTAMPUNIT -49
+#define ERR_RTP_RTCPPACKETBUILDER_NOTINIT -50
+#define ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON -51
+#define ERR_RTP_SCHEDPARAMS_BADFRACTION -52
+#define ERR_RTP_SCHEDPARAMS_BADMINIMUMINTERVAL -53
+#define ERR_RTP_SCHEDPARAMS_INVALIDBANDWIDTH -54
+#define ERR_RTP_SDES_LENGTHTOOBIG -55
+#define ERR_RTP_SDES_MAXPRIVITEMS -56
+#define ERR_RTP_SDES_PREFIXNOTFOUND -57
+#define ERR_RTP_SESSION_ALREADYCREATED -58
+#define ERR_RTP_SESSION_CANTGETLOGINNAME -59
+#define ERR_RTP_SESSION_CANTINITMUTEX -60
+#define ERR_RTP_SESSION_MAXPACKETSIZETOOSMALL -61
+#define ERR_RTP_SESSION_NOTCREATED -62
+#define ERR_RTP_SESSION_UNSUPPORTEDTRANSMISSIONPROTOCOL -63
+#define ERR_RTP_SESSION_USINGPOLLTHREAD -64
+#define ERR_RTP_SOURCES_ALREADYHAVEOWNSSRC -65
+#define ERR_RTP_SOURCES_DONTHAVEOWNSSRC -66
+#define ERR_RTP_SOURCES_ILLEGALSDESTYPE -67
+#define ERR_RTP_SOURCES_SSRCEXISTS -68
+#define ERR_RTP_TRANS_BUFFERLENGTHTOOSMALL -69
+#define ERR_RTP_UDPV4TRANS_ALREADYCREATED -70
+#define ERR_RTP_UDPV4TRANS_ALREADYINIT -71
+#define ERR_RTP_UDPV4TRANS_ALREADYWAITING -72
+#define ERR_RTP_UDPV4TRANS_CANTBINDRTCPSOCKET -73
+#define ERR_RTP_UDPV4TRANS_CANTBINDRTPSOCKET -74
+#define ERR_RTP_UDPV4TRANS_CANTCALCULATELOCALIP -75
+#define ERR_RTP_UDPV4TRANS_CANTCREATEABORTDESCRIPTORS -76
+#define ERR_RTP_UDPV4TRANS_CANTCREATEPIPE -77
+#define ERR_RTP_UDPV4TRANS_CANTCREATESOCKET -78
+#define ERR_RTP_UDPV4TRANS_CANTINITMUTEX -79
+#define ERR_RTP_UDPV4TRANS_CANTSETRTCPRECEIVEBUF -80
+#define ERR_RTP_UDPV4TRANS_CANTSETRTCPTRANSMITBUF -81
+#define ERR_RTP_UDPV4TRANS_CANTSETRTPRECEIVEBUF -82
+#define ERR_RTP_UDPV4TRANS_CANTSETRTPTRANSMITBUF -83
+#define ERR_RTP_UDPV4TRANS_COULDNTJOINMULTICASTGROUP -84
+#define ERR_RTP_UDPV4TRANS_DIFFERENTRECEIVEMODE -85
+#define ERR_RTP_UDPV4TRANS_ERRORINSELECT -86
+#define ERR_RTP_UDPV4TRANS_ILLEGALPARAMETERS -87
+#define ERR_RTP_UDPV4TRANS_INVALIDADDRESSTYPE -88
+#define ERR_RTP_UDPV4TRANS_NOLOCALIPS -89
+#define ERR_RTP_UDPV4TRANS_NOMULTICASTSUPPORT -90
+#define ERR_RTP_UDPV4TRANS_NOSUCHENTRY -91
+#define ERR_RTP_UDPV4TRANS_NOTAMULTICASTADDRESS -92
+#define ERR_RTP_UDPV4TRANS_NOTCREATED -93
+#define ERR_RTP_UDPV4TRANS_NOTINIT -94
+#define ERR_RTP_UDPV4TRANS_NOTWAITING -95
+#define ERR_RTP_UDPV4TRANS_PORTBASENOTEVEN -96
+#define ERR_RTP_UDPV4TRANS_SPECIFIEDSIZETOOBIG -97
+#define ERR_RTP_UDPV6TRANS_ALREADYCREATED -98
+#define ERR_RTP_UDPV6TRANS_ALREADYINIT -99
+#define ERR_RTP_UDPV6TRANS_ALREADYWAITING -100
+#define ERR_RTP_UDPV6TRANS_CANTBINDRTCPSOCKET -101
+#define ERR_RTP_UDPV6TRANS_CANTBINDRTPSOCKET -102
+#define ERR_RTP_UDPV6TRANS_CANTCALCULATELOCALIP -103
+#define ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS -104
+#define ERR_RTP_UDPV6TRANS_CANTCREATEPIPE -105
+#define ERR_RTP_UDPV6TRANS_CANTCREATESOCKET -106
+#define ERR_RTP_UDPV6TRANS_CANTINITMUTEX -107
+#define ERR_RTP_UDPV6TRANS_CANTSETRTCPRECEIVEBUF -108
+#define ERR_RTP_UDPV6TRANS_CANTSETRTCPTRANSMITBUF -109
+#define ERR_RTP_UDPV6TRANS_CANTSETRTPRECEIVEBUF -110
+#define ERR_RTP_UDPV6TRANS_CANTSETRTPTRANSMITBUF -111
+#define ERR_RTP_UDPV6TRANS_COULDNTJOINMULTICASTGROUP -112
+#define ERR_RTP_UDPV6TRANS_DIFFERENTRECEIVEMODE -113
+#define ERR_RTP_UDPV6TRANS_ERRORINSELECT -114
+#define ERR_RTP_UDPV6TRANS_ILLEGALPARAMETERS -115
+#define ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE -116
+#define ERR_RTP_UDPV6TRANS_NOLOCALIPS -117
+#define ERR_RTP_UDPV6TRANS_NOMULTICASTSUPPORT -118
+#define ERR_RTP_UDPV6TRANS_NOSUCHENTRY -119
+#define ERR_RTP_UDPV6TRANS_NOTAMULTICASTADDRESS -120
+#define ERR_RTP_UDPV6TRANS_NOTCREATED -121
+#define ERR_RTP_UDPV6TRANS_NOTINIT -122
+#define ERR_RTP_UDPV6TRANS_NOTWAITING -123
+#define ERR_RTP_UDPV6TRANS_PORTBASENOTEVEN -124
+#define ERR_RTP_UDPV6TRANS_SPECIFIEDSIZETOOBIG -125
+#define ERR_RTP_INTERNALSOURCEDATA_INVALIDPROBATIONTYPE -126
+#define ERR_RTP_SESSION_USERDEFINEDTRANSMITTERNULL -127
+#define ERR_RTP_FAKETRANS_ALREADYCREATED -128
+#define ERR_RTP_FAKETRANS_ALREADYINIT -129
+#define ERR_RTP_FAKETRANS_ALREADYWAITING -130
+#define ERR_RTP_FAKETRANS_CANTBINDRTCPSOCKET -131
+#define ERR_RTP_FAKETRANS_CANTBINDRTPSOCKET -132
+#define ERR_RTP_FAKETRANS_CANTCALCULATELOCALIP -133
+#define ERR_RTP_FAKETRANS_CANTCREATEABORTDESCRIPTORS -134
+#define ERR_RTP_FAKETRANS_CANTCREATEPIPE -135
+#define ERR_RTP_FAKETRANS_CANTCREATESOCKET -136
+#define ERR_RTP_FAKETRANS_CANTINITMUTEX -137
+#define ERR_RTP_FAKETRANS_CANTSETRTCPRECEIVEBUF -138
+#define ERR_RTP_FAKETRANS_CANTSETRTCPTRANSMITBUF -139
+#define ERR_RTP_FAKETRANS_CANTSETRTPRECEIVEBUF -140
+#define ERR_RTP_FAKETRANS_CANTSETRTPTRANSMITBUF -141
+#define ERR_RTP_FAKETRANS_COULDNTJOINMULTICASTGROUP -142
+#define ERR_RTP_FAKETRANS_DIFFERENTRECEIVEMODE -143
+#define ERR_RTP_FAKETRANS_ERRORINSELECT -144
+#define ERR_RTP_FAKETRANS_ILLEGALPARAMETERS -145
+#define ERR_RTP_FAKETRANS_INVALIDADDRESSTYPE -146
+#define ERR_RTP_FAKETRANS_NOLOCALIPS -147
+#define ERR_RTP_FAKETRANS_NOMULTICASTSUPPORT -148
+#define ERR_RTP_FAKETRANS_NOSUCHENTRY -149
+#define ERR_RTP_FAKETRANS_NOTAMULTICASTADDRESS -150
+#define ERR_RTP_FAKETRANS_NOTCREATED -151
+#define ERR_RTP_FAKETRANS_NOTINIT -152
+#define ERR_RTP_FAKETRANS_NOTWAITING -153
+#define ERR_RTP_FAKETRANS_PORTBASENOTEVEN -154
+#define ERR_RTP_FAKETRANS_SPECIFIEDSIZETOOBIG -155
+#define ERR_RTP_FAKETRANS_INVALIDEVENT -156
+#define ERR_RTP_FAKETRANS_SRCADDRNOTSET -157
+#define ERR_RTP_FAKETRANS_NOTNETBUFFER -158
+#define ERR_RTP_FAKETRANS_WAITNOTIMPLEMENTED -159
+
+
+
+#endif // RTPERRORS_H
+
diff --git a/src/rtphashtable.h b/src/rtphashtable.h
new file mode 100644
index 0000000..aa482c0
--- /dev/null
+++ b/src/rtphashtable.h
@@ -0,0 +1,337 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#ifndef RTPHASHTABLE_H
+
+#define RTPHASHTABLE_H
+
+/**
+ * \file rtphashtable.h
+ */
+
+#include "rtperrors.h"
+#include "rtpmemoryobject.h"
+
+#ifdef RTPDEBUG
+#include <iostream>
+#endif // RTPDEBUG
+
+//template<class Element,int GetIndex(const Element &k),int hashsize>
+template<class Element,class GetIndex,int hashsize>
+class RTPHashTable : public RTPMemoryObject
+{
+public:
+ RTPHashTable(RTPMemoryManager *mgr = 0, int memtype = RTPMEM_TYPE_OTHER);
+ ~RTPHashTable() { Clear(); }
+
+ void GotoFirstElement() { curhashelem = firsthashelem; }
+ void GotoLastElement() { curhashelem = lasthashelem; }
+ bool HasCurrentElement() { return (curhashelem == 0)?false:true; }
+ int DeleteCurrentElement();
+ Element &GetCurrentElement() { return curhashelem->GetElement(); }
+ int GotoElement(const Element &e);
+ bool HasElement(const Element &e);
+ void GotoNextElement();
+ void GotoPreviousElement();
+ void Clear();
+
+ int AddElement(const Element &elem);
+ int DeleteElement(const Element &elem);
+
+#ifdef RTPDEBUG
+ void Dump();
+#endif // RTPDEBUG
+private:
+ class HashElement
+ {
+ public:
+ HashElement(const Element &e,int index):element(e) { hashprev = 0; hashnext = 0; listnext = 0; listprev = 0; hashindex = index; }
+ int GetHashIndex() { return hashindex; }
+ Element &GetElement() { return element; }
+#ifdef RTPDEBUG
+ void Dump() { std::cout << "\tHash index " << hashindex << " | Element " << element << std::endl; }
+#endif // RTPDEBUG
+ private:
+ int hashindex;
+ Element element;
+ public:
+ HashElement *hashprev,*hashnext;
+ HashElement *listprev,*listnext;
+ };
+
+ HashElement *table[hashsize];
+ HashElement *firsthashelem,*lasthashelem;
+ HashElement *curhashelem;
+#ifdef RTP_SUPPORT_MEMORYMANAGEMENT
+ int memorytype;
+#endif // RTP_SUPPORT_MEMORYMANAGEMENT
+};
+
+template<class Element,class GetIndex,int hashsize>
+inline RTPHashTable<Element,GetIndex,hashsize>::RTPHashTable(RTPMemoryManager *mgr,int memtype) : RTPMemoryObject(mgr)
+{
+ for (int i = 0 ; i < hashsize ; i++)
+ table[i] = 0;
+ firsthashelem = 0;
+ lasthashelem = 0;
+#ifdef RTP_SUPPORT_MEMORYMANAGEMENT
+ memorytype = memtype;
+#endif // RTP_SUPPORT_MEMORYMANAGEMENT
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline int RTPHashTable<Element,GetIndex,hashsize>::DeleteCurrentElement()
+{
+ if (curhashelem)
+ {
+ HashElement *tmp1,*tmp2;
+ int index;
+
+ // First, relink elements in current hash bucket
+
+ index = curhashelem->GetHashIndex();
+ tmp1 = curhashelem->hashprev;
+ tmp2 = curhashelem->hashnext;
+ if (tmp1 == 0) // no previous element in hash bucket
+ {
+ table[index] = tmp2;
+ if (tmp2 != 0)
+ tmp2->hashprev = 0;
+ }
+ else // there is a previous element in the hash bucket
+ {
+ tmp1->hashnext = tmp2;
+ if (tmp2 != 0)
+ tmp2->hashprev = tmp1;
+ }
+
+ // Relink elements in list
+
+ tmp1 = curhashelem->listprev;
+ tmp2 = curhashelem->listnext;
+ if (tmp1 == 0) // curhashelem is first in list
+ {
+ firsthashelem = tmp2;
+ if (tmp2 != 0)
+ tmp2->listprev = 0;
+ else // curhashelem is also last in list
+ lasthashelem = 0;
+ }
+ else
+ {
+ tmp1->listnext = tmp2;
+ if (tmp2 != 0)
+ tmp2->listprev = tmp1;
+ else // curhashelem is last in list
+ lasthashelem = tmp1;
+ }
+
+ // finally, with everything being relinked, we can delete curhashelem
+ RTPDelete(curhashelem,GetMemoryManager());
+ curhashelem = tmp2; // Set to next element in the list
+ }
+ else
+ return ERR_RTP_HASHTABLE_NOCURRENTELEMENT;
+ return 0;
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline int RTPHashTable<Element,GetIndex,hashsize>::GotoElement(const Element &e)
+{
+ int index;
+ bool found;
+
+ index = GetIndex::GetIndex(e);
+ if (index >= hashsize)
+ return ERR_RTP_HASHTABLE_FUNCTIONRETURNEDINVALIDHASHINDEX;
+
+ curhashelem = table[index];
+ found = false;
+ while(!found && curhashelem != 0)
+ {
+ if (curhashelem->GetElement() == e)
+ found = true;
+ else
+ curhashelem = curhashelem->hashnext;
+ }
+ if (!found)
+ return ERR_RTP_HASHTABLE_ELEMENTNOTFOUND;
+ return 0;
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline bool RTPHashTable<Element,GetIndex,hashsize>::HasElement(const Element &e)
+{
+ int index;
+ bool found;
+ HashElement *tmp;
+
+ index = GetIndex::GetIndex(e);
+ if (index >= hashsize)
+ return false;
+
+ tmp = table[index];
+ found = false;
+ while(!found && tmp != 0)
+ {
+ if (tmp->GetElement() == e)
+ found = true;
+ else
+ tmp = tmp->hashnext;
+ }
+ return found;
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline void RTPHashTable<Element,GetIndex,hashsize>::GotoNextElement()
+{
+ if (curhashelem)
+ curhashelem = curhashelem->listnext;
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline void RTPHashTable<Element,GetIndex,hashsize>::GotoPreviousElement()
+{
+ if (curhashelem)
+ curhashelem = curhashelem->listprev;
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline void RTPHashTable<Element,GetIndex,hashsize>::Clear()
+{
+ HashElement *tmp1,*tmp2;
+
+ for (int i = 0 ; i < hashsize ; i++)
+ table[i] = 0;
+
+ tmp1 = firsthashelem;
+ while (tmp1 != 0)
+ {
+ tmp2 = tmp1->listnext;
+ RTPDelete(tmp1,GetMemoryManager());
+ tmp1 = tmp2;
+ }
+ firsthashelem = 0;
+ lasthashelem = 0;
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline int RTPHashTable<Element,GetIndex,hashsize>::AddElement(const Element &elem)
+{
+ int index;
+ bool found;
+ HashElement *e,*newelem;
+
+ index = GetIndex::GetIndex(elem);
+ if (index >= hashsize)
+ return ERR_RTP_HASHTABLE_FUNCTIONRETURNEDINVALIDHASHINDEX;
+
+ e = table[index];
+ found = false;
+ while(!found && e != 0)
+ {
+ if (e->GetElement() == elem)
+ found = true;
+ else
+ e = e->hashnext;
+ }
+ if (found)
+ return ERR_RTP_HASHTABLE_ELEMENTALREADYEXISTS;
+
+ // Okay, the key doesn't exist, so we can add the new element in the hash table
+
+ newelem = RTPNew(GetMemoryManager(),memorytype) HashElement(elem,index);
+ if (newelem == 0)
+ return ERR_RTP_OUTOFMEM;
+
+ e = table[index];
+ table[index] = newelem;
+ newelem->hashnext = e;
+ if (e != 0)
+ e->hashprev = newelem;
+
+ // Now, we still got to add it to the linked list
+
+ if (firsthashelem == 0)
+ {
+ firsthashelem = newelem;
+ lasthashelem = newelem;
+ }
+ else // there already are some elements in the list
+ {
+ lasthashelem->listnext = newelem;
+ newelem->listprev = lasthashelem;
+ lasthashelem = newelem;
+ }
+ return 0;
+}
+
+template<class Element,class GetIndex,int hashsize>
+inline int RTPHashTable<Element,GetIndex,hashsize>::DeleteElement(const Element &elem)
+{
+ int status;
+
+ status = GotoElement(elem);
+ if (status < 0)
+ return status;
+ return DeleteCurrentElement();
+}
+
+#ifdef RTPDEBUG
+template<class Element,class GetIndex,int hashsize>
+inline void RTPHashTable<Element,GetIndex,hashsize>::Dump()
+{
+ HashElement *e;
+
+ std::cout << "DUMPING TABLE CONTENTS:" << std::endl;
+ for (int i = 0 ; i < hashsize ; i++)
+ {
+ e = table[i];
+ while (e != 0)
+ {
+ e->Dump();
+ e = e->hashnext;
+ }
+ }
+
+ std::cout << "DUMPING LIST CONTENTS:" << std::endl;
+ e = firsthashelem;
+ while (e != 0)
+ {
+ e->Dump();
+ e = e->listnext;
+ }
+}
+#endif // RTPDEBUG
+
+#endif // RTPHASHTABLE_H
+
diff --git a/src/rtpinternalsourcedata.cpp b/src/rtpinternalsourcedata.cpp
new file mode 100644
index 0000000..d023f7d
--- /dev/null
+++ b/src/rtpinternalsourcedata.cpp
@@ -0,0 +1,282 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtpinternalsourcedata.h"
+#include "rtppacket.h"
+#include <string.h>
+
+#include "rtpdebug.h"
+
+#define RTPINTERNALSOURCEDATA_MAXPROBATIONPACKETS 32
+
+RTPInternalSourceData::RTPInternalSourceData(uint32_t ssrc,RTPSources::ProbationType probtype,RTPMemoryManager *mgr):RTPSourceData(ssrc,mgr)
+{
+#ifdef RTP_SUPPORT_PROBATION
+ probationtype = probtype;
+#endif // RTP_SUPPORT_PROBATION
+}
+
+RTPInternalSourceData::~RTPInternalSourceData()
+{
+}
+
+// The following function should delete rtppack if necessary
+int RTPInternalSourceData::ProcessRTPPacket(RTPPacket *rtppack,const RTPTime &receivetime,bool *stored)
+{
+ bool accept,onprobation,applyprobation;
+ double tsunit;
+
+ *stored = false;
+
+ if (timestampunit < 0)
+ tsunit = INF_GetEstimatedTimestampUnit();
+ else
+ tsunit = timestampunit;
+
+#ifdef RTP_SUPPORT_PROBATION
+ if (validated) // If the source is our own process, we can already be validated. No
+ applyprobation = false; // probation should be applied in that case.
+ else
+ {
+ if (probationtype == RTPSources::NoProbation)
+ applyprobation = false;
+ else
+ applyprobation = true;
+ }
+#else
+ applyprobation = false;
+#endif // RTP_SUPPORT_PROBATION
+
+ stats.ProcessPacket(rtppack,receivetime,tsunit,ownssrc,&accept,applyprobation,&onprobation);
+
+#ifdef RTP_SUPPORT_PROBATION
+ switch (probationtype)
+ {
+ case RTPSources::ProbationStore:
+ if (!(onprobation || accept))
+ return 0;
+ if (accept)
+ validated = true;
+ break;
+ case RTPSources::ProbationDiscard:
+ case RTPSources::NoProbation:
+ if (!accept)
+ return 0;
+ validated = true;
+ break;
+ default:
+ return ERR_RTP_INTERNALSOURCEDATA_INVALIDPROBATIONTYPE;
+ }
+#else
+ if (!accept)
+ return 0;
+ validated = true;
+#endif // RTP_SUPPORT_PROBATION;
+
+ if (validated && !ownssrc) // for own ssrc these variables depend on the outgoing packets, not on the incoming
+ issender = true;
+
+ // Now, we can place the packet in the queue
+
+ if (packetlist.empty())
+ {
+ *stored = true;
+ packetlist.push_back(rtppack);
+ return 0;
+ }
+
+ if (!validated) // still on probation
+ {
+ // Make sure that we don't buffer too much packets to avoid wasting memory
+ // on a bad source. Delete the packet in the queue with the lowest sequence
+ // number.
+ if (packetlist.size() == RTPINTERNALSOURCEDATA_MAXPROBATIONPACKETS)
+ {
+ RTPPacket *p = *(packetlist.begin());
+ packetlist.pop_front();
+ RTPDelete(p,GetMemoryManager());
+ }
+ }
+
+ // find the right position to insert the packet
+
+ std::list<RTPPacket*>::iterator it,start;
+ bool done = false;
+ uint32_t newseqnr = rtppack->GetExtendedSequenceNumber();
+
+ it = packetlist.end();
+ --it;
+ start = packetlist.begin();
+
+ while (!done)
+ {
+ RTPPacket *p;
+ uint32_t seqnr;
+
+ p = *it;
+ seqnr = p->GetExtendedSequenceNumber();
+ if (seqnr > newseqnr)
+ {
+ if (it != start)
+ --it;
+ else // we're at the start of the list
+ {
+ *stored = true;
+ done = true;
+ packetlist.push_front(rtppack);
+ }
+ }
+ else if (seqnr < newseqnr) // insert after this packet
+ {
+ ++it;
+ packetlist.insert(it,rtppack);
+ done = true;
+ *stored = true;
+ }
+ else // they're equal !! Drop packet
+ {
+ done = true;
+ }
+ }
+
+ return 0;
+}
+
+int RTPInternalSourceData::ProcessSDESItem(uint8_t sdesid,const uint8_t *data,size_t itemlen,const RTPTime &receivetime,bool *cnamecollis)
+{
+ *cnamecollis = false;
+
+ stats.SetLastMessageTime(receivetime);
+
+ switch(sdesid)
+ {
+ case RTCP_SDES_ID_CNAME:
+ {
+ size_t curlen;
+ uint8_t *oldcname;
+
+ // NOTE: we're going to make sure that the CNAME is only set once.
+ oldcname = SDESinf.GetCNAME(&curlen);
+ if (curlen == 0)
+ {
+ // if CNAME is set, the source is validated
+ SDESinf.SetCNAME(data,itemlen);
+ validated = true;
+ }
+ else // check if this CNAME is equal to the one that is already present
+ {
+ if (curlen != itemlen)
+ *cnamecollis = true;
+ else
+ {
+ if (memcmp(data,oldcname,itemlen) != 0)
+ *cnamecollis = true;
+ }
+ }
+ }
+ break;
+ case RTCP_SDES_ID_NAME:
+ {
+ uint8_t *oldname;
+ size_t oldlen;
+
+ oldname = SDESinf.GetName(&oldlen);
+ if (oldlen == 0) // Name not set
+ return SDESinf.SetName(data,itemlen);
+ }
+ break;
+ case RTCP_SDES_ID_EMAIL:
+ {
+ uint8_t *oldemail;
+ size_t oldlen;
+
+ oldemail = SDESinf.GetEMail(&oldlen);
+ if (oldlen == 0)
+ return SDESinf.SetEMail(data,itemlen);
+ }
+ break;
+ case RTCP_SDES_ID_PHONE:
+ return SDESinf.SetPhone(data,itemlen);
+ case RTCP_SDES_ID_LOCATION:
+ return SDESinf.SetLocation(data,itemlen);
+ case RTCP_SDES_ID_TOOL:
+ {
+ uint8_t *oldtool;
+ size_t oldlen;
+
+ oldtool = SDESinf.GetTool(&oldlen);
+ if (oldlen == 0)
+ return SDESinf.SetTool(data,itemlen);
+ }
+ break;
+ case RTCP_SDES_ID_NOTE:
+ stats.SetLastNoteTime(receivetime);
+ return SDESinf.SetNote(data,itemlen);
+ }
+ return 0;
+}
+
+#ifdef RTP_SUPPORT_SDESPRIV
+
+int RTPInternalSourceData::ProcessPrivateSDESItem(const uint8_t *prefix,size_t prefixlen,const uint8_t *value,size_t valuelen,const RTPTime &receivetime)
+{
+ int status;
+
+ stats.SetLastMessageTime(receivetime);
+ status = SDESinf.SetPrivateValue(prefix,prefixlen,value,valuelen);
+ if (status == ERR_RTP_SDES_MAXPRIVITEMS)
+ return 0; // don't stop processing just because the number of items is full
+ return status;
+}
+
+#endif // RTP_SUPPORT_SDESPRIV
+
+int RTPInternalSourceData::ProcessBYEPacket(const uint8_t *reason,size_t reasonlen,const RTPTime &receivetime)
+{
+ if (byereason)
+ {
+ RTPDeleteByteArray(byereason,GetMemoryManager());
+ byereason = 0;
+ byereasonlen = 0;
+ }
+
+ byetime = receivetime;
+ byereason = RTPNew(GetMemoryManager(),RTPMEM_TYPE_BUFFER_RTCPBYEREASON) uint8_t[reasonlen];
+ if (byereason == 0)
+ return ERR_RTP_OUTOFMEM;
+ memcpy(byereason,reason,reasonlen);
+ byereasonlen = reasonlen;
+ receivedbye = true;
+ stats.SetLastMessageTime(receivetime);
+ return 0;
+}
+
diff --git a/src/rtpinternalsourcedata.h b/src/rtpinternalsourcedata.h
new file mode 100644
index 0000000..7b01016
--- /dev/null
+++ b/src/rtpinternalsourcedata.h
@@ -0,0 +1,130 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpinternalsourcedata.h
+ */
+
+#ifndef RTPINTERNALSOURCEDATA_H
+
+#define RTPINTERNALSOURCEDATA_H
+
+#include "rtpconfig.h"
+#include "rtpsourcedata.h"
+#include "rtpaddress.h"
+#include "rtptimeutilities.h"
+#include "rtpsources.h"
+
+class RTPInternalSourceData : public RTPSourceData
+{
+public:
+ RTPInternalSourceData(uint32_t ssrc, RTPSources::ProbationType probtype, RTPMemoryManager *mgr = 0);
+ ~RTPInternalSourceData();
+
+ int ProcessRTPPacket(RTPPacket *rtppack,const RTPTime &receivetime,bool *stored);
+ void ProcessSenderInfo(const RTPNTPTime &ntptime,uint32_t rtptime,uint32_t packetcount,
+ uint32_t octetcount,const RTPTime &receivetime) { SRprevinf = SRinf; SRinf.Set(ntptime,rtptime,packetcount,octetcount,receivetime); stats.SetLastMessageTime(receivetime); }
+ void ProcessReportBlock(uint8_t fractionlost,int32_t lostpackets,uint32_t exthighseqnr,
+ uint32_t jitter,uint32_t lsr,uint32_t dlsr,
+ const RTPTime &receivetime) { RRprevinf = RRinf; RRinf.Set(fractionlost,lostpackets,exthighseqnr,jitter,lsr,dlsr,receivetime); stats.SetLastMessageTime(receivetime); }
+ void UpdateMessageTime(const RTPTime &receivetime) { stats.SetLastMessageTime(receivetime); }
+ int ProcessSDESItem(uint8_t sdesid,const uint8_t *data,size_t itemlen,const RTPTime &receivetime,bool *cnamecollis);
+#ifdef RTP_SUPPORT_SDESPRIV
+ int ProcessPrivateSDESItem(const uint8_t *prefix,size_t prefixlen,const uint8_t *value,size_t valuelen,const RTPTime &receivetime);
+#endif // RTP_SUPPORT_SDESPRIV
+ int ProcessBYEPacket(const uint8_t *reason,size_t reasonlen,const RTPTime &receivetime);
+
+ int SetRTPDataAddress(const RTPAddress *a);
+ int SetRTCPDataAddress(const RTPAddress *a);
+
+ void ClearSenderFlag() { issender = false; }
+ void SentRTPPacket() { if (!ownssrc) return; RTPTime t = RTPTime::CurrentTime(); issender = true; stats.SetLastRTPPacketTime(t); stats.SetLastMessageTime(t); }
+ void SetOwnSSRC() { ownssrc = true; validated = true; }
+ void SetCSRC() { validated = true; iscsrc = true; }
+ void ClearNote() { SDESinf.SetNote(0,0); }
+
+#ifdef RTP_SUPPORT_PROBATION
+private:
+ RTPSources::ProbationType probationtype;
+#endif // RTP_SUPPORT_PROBATION
+};
+
+inline int RTPInternalSourceData::SetRTPDataAddress(const RTPAddress *a)
+{
+ if (a == 0)
+ {
+ if (rtpaddr)
+ {
+ RTPDelete(rtpaddr,GetMemoryManager());
+ rtpaddr = 0;
+ }
+ }
+ else
+ {
+ RTPAddress *newaddr = a->CreateCopy(GetMemoryManager());
+ if (newaddr == 0)
+ return ERR_RTP_OUTOFMEM;
+
+ if (rtpaddr && a != rtpaddr)
+ RTPDelete(rtpaddr,GetMemoryManager());
+ rtpaddr = newaddr;
+ }
+ isrtpaddrset = true;
+ return 0;
+}
+
+inline int RTPInternalSourceData::SetRTCPDataAddress(const RTPAddress *a)
+{
+ if (a == 0)
+ {
+ if (rtcpaddr)
+ {
+ RTPDelete(rtcpaddr,GetMemoryManager());
+ rtcpaddr = 0;
+ }
+ }
+ else
+ {
+ RTPAddress *newaddr = a->CreateCopy(GetMemoryManager());
+ if (newaddr == 0)
+ return ERR_RTP_OUTOFMEM;
+
+ if (rtcpaddr && a != rtcpaddr)
+ RTPDelete(rtcpaddr,GetMemoryManager());
+ rtcpaddr = newaddr;
+ }
+ isrtcpaddrset = true;
+ return 0;
+}
+
+#endif // RTPINTERNALSOURCEDATA_H
+
diff --git a/src/rtpipv4address.cpp b/src/rtpipv4address.cpp
new file mode 100644
index 0000000..de5fcb9
--- /dev/null
+++ b/src/rtpipv4address.cpp
@@ -0,0 +1,83 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtpipv4address.h"
+#include "rtpmemorymanager.h"
+#ifdef RTPDEBUG
+ #include "rtpdefines.h"
+ #include <stdio.h>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+bool RTPIPv4Address::IsSameAddress(const RTPAddress *addr) const
+{
+ if (addr == 0)
+ return false;
+ if (addr->GetAddressType() != IPv4Address)
+ return false;
+
+ const RTPIPv4Address *addr2 = (const RTPIPv4Address *)addr;
+ if (addr2->GetIP() == ip && addr2->GetPort() == port)
+ return true;
+ return false;
+}
+
+bool RTPIPv4Address::IsFromSameHost(const RTPAddress *addr) const
+{
+ if (addr == 0)
+ return false;
+ if (addr->GetAddressType() != IPv4Address)
+ return false;
+
+ const RTPIPv4Address *addr2 = (const RTPIPv4Address *)addr;
+ if (addr2->GetIP() == ip)
+ return true;
+ return false;
+}
+
+RTPAddress *RTPIPv4Address::CreateCopy(RTPMemoryManager *mgr) const
+{
+ RTPIPv4Address *a = RTPNew(mgr,RTPMEM_TYPE_CLASS_RTPADDRESS) RTPIPv4Address(ip,port);
+ return a;
+}
+
+#ifdef RTPDEBUG
+std::string RTPIPv4Address::GetAddressString() const
+{
+ char str[24];
+
+ RTP_SNPRINTF(str,24,"%d.%d.%d.%d:%d",(int)((ip>>24)&0xFF),(int)((ip>>16)&0xFF),(int)((ip>>8)&0xFF),
+ (int)(ip&0xFF),(int)port);
+ return std::string(str);
+}
+#endif // RTPDEBUG
diff --git a/src/rtpipv4address.h b/src/rtpipv4address.h
new file mode 100644
index 0000000..08845fd
--- /dev/null
+++ b/src/rtpipv4address.h
@@ -0,0 +1,90 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpipv4address.h
+ */
+
+#ifndef RTPIPV4ADDRESS_H
+
+#define RTPIPV4ADDRESS_H
+
+#include "rtpconfig.h"
+#include "rtpaddress.h"
+#include "rtptypes.h"
+
+class RTPMemoryManager;
+
+/** Represents an IPv4 IP address and port.
+ * This class is used by the UDP over IPv4 transmission component.
+ * When an RTPIPv4Address is used in one of the multicast functions of the transmitter, the port
+ * number is ignored. When an instance is used in one of the accept or ignore functions of the
+ * transmitter, a zero port number represents all ports for the specified IP address.
+ */
+class RTPIPv4Address : public RTPAddress
+{
+public:
+ /** Creates an instance with IP address \c ip and port number \c port (both are interpreted in host byte order). */
+ RTPIPv4Address(uint32_t ip = 0, uint16_t port = 0):RTPAddress(IPv4Address) { RTPIPv4Address::ip = ip; RTPIPv4Address::port = port; }
+
+ /** Creates an instance with IP address \c ip and port number \c port (\c port is interpreted in host byte order). */
+ RTPIPv4Address(const uint8_t ip[4],uint16_t port = 0):RTPAddress(IPv4Address) { RTPIPv4Address::ip = (uint32_t)ip[3]; RTPIPv4Address::ip |= (((uint32_t)ip[2])<<8); RTPIPv4Address::ip |= (((uint32_t)ip[1])<<16); RTPIPv4Address::ip |= (((uint32_t)ip[0])<<24); RTPIPv4Address::port = port; }
+ ~RTPIPv4Address() { }
+
+ /** Sets the IP address for this instance to \c ip which is assumed to be in host byte order. */
+ void SetIP(uint32_t ip) { RTPIPv4Address::ip = ip; }
+
+ /** Sets the IP address of this instance to \c ip. */
+ void SetIP(const uint8_t ip[4]) { RTPIPv4Address::ip = (uint32_t)ip[3]; RTPIPv4Address::ip |= (((uint32_t)ip[2])<<8); RTPIPv4Address::ip |= (((uint32_t)ip[1])<<16); RTPIPv4Address::ip |= (((uint32_t)ip[0])<<24); }
+
+ /** Sets the port number for this instance to \c port which is interpreted in host byte order. */
+ void SetPort(uint16_t port) { RTPIPv4Address::port = port; }
+
+ /** Returns the IP address contained in this instance in host byte order. */
+ uint32_t GetIP() const { return ip; }
+
+ /** Returns the port number of this instance in host byte order. */
+ uint16_t GetPort() const { return port; }
+
+ RTPAddress *CreateCopy(RTPMemoryManager *mgr) const;
+ bool IsSameAddress(const RTPAddress *addr) const;
+ bool IsFromSameHost(const RTPAddress *addr) const;
+#ifdef RTPDEBUG
+ std::string GetAddressString() const;
+#endif // RTPDEBUG
+private:
+ uint32_t ip;
+ uint16_t port;
+};
+
+#endif // RTPIPV4ADDRESS_H
+
diff --git a/src/rtpipv4destination.h b/src/rtpipv4destination.h
new file mode 100644
index 0000000..a31243a
--- /dev/null
+++ b/src/rtpipv4destination.h
@@ -0,0 +1,108 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpipv4destination.h
+ */
+
+#ifndef RTPIPV4DESTINATION_H
+
+#define RTPIPV4DESTINATION_H
+
+#include "rtpconfig.h"
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <sys/socket.h>
+#endif // WIN32
+#ifdef RTPDEBUG
+ #include "rtpdefines.h"
+ #include <stdio.h>
+ #include <string>
+#endif // RTPDEBUG
+#include <string.h>
+
+class RTPIPv4Destination
+{
+public:
+ RTPIPv4Destination(uint32_t ip,uint16_t rtpportbase)
+ {
+ memset(&rtpaddr,0,sizeof(struct sockaddr_in));
+ memset(&rtcpaddr,0,sizeof(struct sockaddr_in));
+
+ rtpaddr.sin_family = AF_INET;
+ rtpaddr.sin_port = htons(rtpportbase);
+ rtpaddr.sin_addr.s_addr = htonl(ip);
+
+ rtcpaddr.sin_family = AF_INET;
+ rtcpaddr.sin_port = htons(rtpportbase+1);
+ rtcpaddr.sin_addr.s_addr = htonl(ip);
+
+ RTPIPv4Destination::ip = ip;
+ }
+
+ bool operator==(const RTPIPv4Destination &src) const
+ {
+ if (rtpaddr.sin_addr.s_addr == src.rtpaddr.sin_addr.s_addr && rtpaddr.sin_port == src.rtpaddr.sin_port)
+ return true;
+ return false;
+ }
+ uint32_t GetIP() const { return ip; }
+ // nbo = network byte order
+ uint32_t GetIP_NBO() const { return rtpaddr.sin_addr.s_addr; }
+ uint16_t GetRTPPort_NBO() const { return rtpaddr.sin_port; }
+ uint16_t GetRTCPPort_NBO() const { return rtcpaddr.sin_port; }
+ const struct sockaddr_in *GetRTPSockAddr() const { return &rtpaddr; }
+ const struct sockaddr_in *GetRTCPSockAddr() const { return &rtcpaddr; }
+#ifdef RTPDEBUG
+ std::string GetDestinationString() const;
+#endif // RTPDEBUG
+private:
+ uint32_t ip;
+ struct sockaddr_in rtpaddr;
+ struct sockaddr_in rtcpaddr;
+};
+
+#ifdef RTPDEBUG
+inline std::string RTPIPv4Destination::GetDestinationString() const
+{
+ char str[24];
+ uint32_t ip = ipaddr_hbo;
+ uint16_t portbase = ntohs(rtpport_nbo);
+
+ RTP_SNPRINTF(str,24,"%d.%d.%d.%d:%d",(int)((ip>>24)&0xFF),(int)((ip>>16)&0xFF),(int)((ip>>8)&0xFF),(int)(ip&0xFF),(int)(portbase));
+ return std::string(str);
+}
+#endif // RTPDEBUG
+
+#endif // RTPIPV4DESTINATION_H
+
diff --git a/src/rtpipv6address.cpp b/src/rtpipv6address.cpp
new file mode 100644
index 0000000..a2a685b
--- /dev/null
+++ b/src/rtpipv6address.cpp
@@ -0,0 +1,108 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtpipv6address.h"
+#include "rtpmemorymanager.h"
+
+#ifdef RTP_SUPPORT_IPV6
+
+#ifdef RTPDEBUG
+ #include "rtpdefines.h"
+ #include <stdio.h>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+RTPAddress *RTPIPv6Address::CreateCopy(RTPMemoryManager *mgr) const
+{
+ RTPIPv6Address *newaddr = RTPNew(mgr,RTPMEM_TYPE_CLASS_RTPADDRESS) RTPIPv6Address(ip,port);
+ return newaddr;
+}
+
+bool RTPIPv6Address::IsSameAddress(const RTPAddress *addr) const
+{
+ if (addr == 0)
+ return false;
+ if (addr->GetAddressType() != RTPAddress::IPv6Address)
+ return false;
+
+ const RTPIPv6Address *addr2 = (const RTPIPv6Address *)addr;
+ const uint8_t *ip2 = addr2->ip.s6_addr;
+
+ if (port != addr2->port)
+ return false;
+
+ for (int i = 0 ; i < 16 ; i++)
+ {
+ if (ip.s6_addr[i] != ip2[i])
+ return false;
+ }
+ return true;
+}
+
+bool RTPIPv6Address::IsFromSameHost(const RTPAddress *addr) const
+{
+ if (addr == 0)
+ return false;
+ if (addr->GetAddressType() != RTPAddress::IPv6Address)
+ return false;
+
+ const RTPIPv6Address *addr2 = (const RTPIPv6Address *)addr;
+ const uint8_t *ip2 = addr2->ip.s6_addr;
+ for (int i = 0 ; i < 16 ; i++)
+ {
+ if (ip.s6_addr[i] != ip2[i])
+ return false;
+ }
+ return true;
+}
+
+#ifdef RTPDEBUG
+std::string RTPIPv6Address::GetAddressString() const
+{
+ char str[48];
+ uint16_t ip16[8];
+ int i,j;
+
+ for (i = 0,j = 0 ; j < 8 ; j++,i += 2)
+ {
+ ip16[j] = (((uint16_t)ip.s6_addr[i])<<8);
+ ip16[j] |= ((uint16_t)ip.s6_addr[i+1]);
+ }
+
+ RTP_SNPRINTF(str,48,"%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X/%d",(int)ip16[0],(int)ip16[1],(int)ip16[2],(int)ip16[3],(int)ip16[4],(int)ip16[5],(int)ip16[6],(int)ip16[7],(int)port);
+ return std::string(str);
+}
+#endif // RTPDEBUG
+
+#endif // RTP_SUPPORT_IPV6
+
diff --git a/src/rtpipv6address.h b/src/rtpipv6address.h
new file mode 100644
index 0000000..ef434c9
--- /dev/null
+++ b/src/rtpipv6address.h
@@ -0,0 +1,105 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpipv6address.h
+ */
+
+#ifndef RTPIPV6ADDRESS_H
+
+#define RTPIPV6ADDRESS_H
+
+#include "rtpconfig.h"
+
+#ifdef RTP_SUPPORT_IPV6
+
+#include "rtpaddress.h"
+#include "rtptypes.h"
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ #include <netinet/in.h>
+#endif // WIN32
+
+/** Represents an IPv6 IP address and port.
+ * This class is used by the UDP over IPv4 transmission component.
+ * When an RTPIPv6Address is used in one of the multicast functions of the
+ * transmitter, the port number is ignored. When an instance is used in one of
+ * the accept or ignore functions of the transmitter, a zero port number represents
+ * all ports for the specified IP address.
+ */
+class RTPIPv6Address : public RTPAddress
+{
+public:
+ /** Creates an instance with IP address and port number set to zero. */
+ RTPIPv6Address():RTPAddress(IPv6Address) { for (int i = 0 ; i < 16 ; i++) ip.s6_addr[i] = 0; port = 0; }
+
+ /** Creates an instance with IP address \c ip and port number \c port (the port number is assumed to be in
+ * host byte order). */
+ RTPIPv6Address(const uint8_t ip[16],uint16_t port = 0):RTPAddress(IPv6Address) { SetIP(ip); RTPIPv6Address::port = port; }
+
+ /** Creates an instance with IP address \c ip and port number \c port (the port number is assumed to be in
+ * host byte order). */
+ RTPIPv6Address(in6_addr ip,uint16_t port = 0):RTPAddress(IPv6Address) { RTPIPv6Address::ip = ip; RTPIPv6Address::port = port; }
+ ~RTPIPv6Address() { }
+
+ /** Sets the IP address for this instance to \c ip. */
+ void SetIP(in6_addr ip) { RTPIPv6Address::ip = ip; }
+
+ /** Sets the IP address for this instance to \c ip. */
+ void SetIP(const uint8_t ip[16]) { for (int i = 0 ; i < 16 ; i++) RTPIPv6Address::ip.s6_addr[i] = ip[i]; }
+
+ /** Sets the port number for this instance to \c port, which is interpreted in host byte order. */
+ void SetPort(uint16_t port) { RTPIPv6Address::port = port; }
+
+ /** Copies the IP address of this instance in \c ip. */
+ void GetIP(uint8_t ip[16]) const { for (int i = 0 ; i < 16 ; i++) ip[i] = RTPIPv6Address::ip.s6_addr[i]; }
+
+ /** Returns the IP address of this instance. */
+ in6_addr GetIP() const { return ip; }
+
+ /** Returns the port number contained in this instance in host byte order. */
+ uint16_t GetPort() const { return port; }
+
+ RTPAddress *CreateCopy(RTPMemoryManager *mgr) const;
+ bool IsSameAddress(const RTPAddress *addr) const;
+ bool IsFromSameHost(const RTPAddress *addr) const;
+#ifdef RTPDEBUG
+ std::string GetAddressString() const;
+#endif // RTPDEBUG
+private:
+ in6_addr ip;
+ uint16_t port;
+};
+
+#endif // RTP_SUPPORT_IPV6
+
+#endif // RTPIPV6ADDRESS_H
+
diff --git a/src/rtpipv6destination.h b/src/rtpipv6destination.h
new file mode 100644
index 0000000..4716b08
--- /dev/null
+++ b/src/rtpipv6destination.h
@@ -0,0 +1,105 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpipv6destination.h
+ */
+
+#ifndef RTPIPV6DESTINATION_H
+
+#define RTPIPV6DESTINATION_H
+
+#include "rtpconfig.h"
+
+#ifdef RTP_SUPPORT_IPV6
+
+#include "rtptypes.h"
+#include <string.h>
+#ifndef WIN32
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <sys/socket.h>
+#endif // WIN32
+#ifdef RTPDEBUG
+ #include "rtpdefines.h"
+ #include <stdio.h>
+ #include <string>
+#endif // RTPDEBUG
+
+class RTPIPv6Destination
+{
+public:
+ RTPIPv6Destination(in6_addr ip,uint16_t portbase)
+ {
+ memset(&rtpaddr,0,sizeof(struct sockaddr_in6));
+ memset(&rtcpaddr,0,sizeof(struct sockaddr_in6));
+ rtpaddr.sin6_family = AF_INET6;
+ rtpaddr.sin6_port = htons(portbase);
+ rtpaddr.sin6_addr = ip;
+ rtcpaddr.sin6_family = AF_INET6;
+ rtcpaddr.sin6_port = htons(portbase+1);
+ rtcpaddr.sin6_addr = ip;
+ }
+ in6_addr GetIP() const { return rtpaddr.sin6_addr; }
+ bool operator==(const RTPIPv6Destination &src) const
+ {
+ if (rtpaddr.sin6_port == src.rtpaddr.sin6_port && (memcmp(&(src.rtpaddr.sin6_addr),&(rtpaddr.sin6_addr),sizeof(in6_addr)) == 0))
+ return true;
+ return false;
+ }
+ const struct sockaddr_in6 *GetRTPSockAddr() const { return &rtpaddr; }
+ const struct sockaddr_in6 *GetRTCPSockAddr() const { return &rtcpaddr; }
+#ifdef RTPDEBUG
+ std::string GetDestinationString() const;
+#endif // RTPDEBUG
+private:
+ struct sockaddr_in6 rtpaddr;
+ struct sockaddr_in6 rtcpaddr;
+};
+
+#ifdef RTPDEBUG
+inline std::string RTPIPv6Destination::GetDestinationString() const
+{
+ uint16_t ip16[8];
+ char str[48];
+ uint16_t portbase = ntohs(rtpport_nbo);
+ int i,j;
+ for (i = 0,j = 0 ; j < 8 ; j++,i += 2) { ip16[j] = (((uint16_t)ip.s6_addr[i])<<8); ip16[j] |= ((uint16_t)ip.s6_addr[i+1]); }
+ RTP_SNPRINTF(str,48,"%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X/%d",(int)ip16[0],(int)ip16[1],(int)ip16[2],(int)ip16[3],(int)ip16[4],(int)ip16[5],(int)ip16[6],(int)ip16[7],(int)portbase);
+ return std::string(str);
+}
+#endif // RTPDEBUG
+
+#endif // RTP_SUPPORT_IPV6
+
+#endif // RTPIPV6DESTINATION_H
+
diff --git a/src/rtpkeyhashtable.h b/src/rtpkeyhashtable.h
new file mode 100644
index 0000000..2ea138f
--- /dev/null
+++ b/src/rtpkeyhashtable.h
@@ -0,0 +1,339 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpkeyhashtable.h
+ */
+
+#ifndef RTPKEYHASHTABLE_H
+
+#define RTPKEYHASHTABLE_H
+
+#include "rtpconfig.h"
+#include "rtperrors.h"
+#include "rtpmemoryobject.h"
+
+#ifdef RTPDEBUG
+#include <iostream>
+#endif // RTPDEBUG
+
+template<class Key,class Element,class GetIndex,int hashsize>
+class RTPKeyHashTable : public RTPMemoryObject
+{
+public:
+ RTPKeyHashTable(RTPMemoryManager *mgr = 0,int memtype = RTPMEM_TYPE_OTHER);
+ ~RTPKeyHashTable() { Clear(); }
+
+ void GotoFirstElement() { curhashelem = firsthashelem; }
+ void GotoLastElement() { curhashelem = lasthashelem; }
+ bool HasCurrentElement() { return (curhashelem == 0)?false:true; }
+ int DeleteCurrentElement();
+ Element &GetCurrentElement() { return curhashelem->GetElement(); }
+ Key &GetCurrentKey() { return curhashelem->GetKey(); }
+ int GotoElement(const Key &k);
+ bool HasElement(const Key &k);
+ void GotoNextElement();
+ void GotoPreviousElement();
+ void Clear();
+
+ int AddElement(const Key &k,const Element &elem);
+ int DeleteElement(const Key &k);
+
+#ifdef RTPDEBUG
+ void Dump();
+#endif // RTPDEBUG
+private:
+ class HashElement
+ {
+ public:
+ HashElement(const Key &k,const Element &e,int index):key(k),element(e) { hashprev = 0; hashnext = 0; listnext = 0; listprev = 0; hashindex = index; }
+ int GetHashIndex() { return hashindex; }
+ Key &GetKey() { return key; }
+ Element &GetElement() { return element; }
+#ifdef RTPDEBUG
+ void Dump() { std::cout << "\tHash index " << hashindex << " | Key " << key << " | Element " << element << std::endl; }
+#endif // RTPDEBUG
+ private:
+ int hashindex;
+ Key key;
+ Element element;
+ public:
+ HashElement *hashprev,*hashnext;
+ HashElement *listprev,*listnext;
+ };
+
+ HashElement *table[hashsize];
+ HashElement *firsthashelem,*lasthashelem;
+ HashElement *curhashelem;
+#ifdef RTP_SUPPORT_MEMORYMANAGEMENT
+ int memorytype;
+#endif // RTP_SUPPORT_MEMORYMANAGEMENT
+};
+
+template<class Key,class Element,class GetIndex,int hashsize>
+inline RTPKeyHashTable<Key,Element,GetIndex,hashsize>::RTPKeyHashTable(RTPMemoryManager *mgr,int memtype) : RTPMemoryObject(mgr)
+{
+ for (int i = 0 ; i < hashsize ; i++)
+ table[i] = 0;
+ firsthashelem = 0;
+ lasthashelem = 0;
+#ifdef RTP_SUPPORT_MEMORYMANAGEMENT
+ memorytype = memtype;
+#endif // RTP_SUPPORT_MEMORYMANAGEMENT
+}
+
+template<class Key,class Element,class GetIndex,int hashsize>
+inline int RTPKeyHashTable<Key,Element,GetIndex,hashsize>::DeleteCurrentElement()
+{
+ if (curhashelem)
+ {
+ HashElement *tmp1,*tmp2;
+ int index;
+
+ // First, relink elements in current hash bucket
+
+ index = curhashelem->GetHashIndex();
+ tmp1 = curhashelem->hashprev;
+ tmp2 = curhashelem->hashnext;
+ if (tmp1 == 0) // no previous element in hash bucket
+ {
+ table[index] = tmp2;
+ if (tmp2 != 0)
+ tmp2->hashprev = 0;
+ }
+ else // there is a previous element in the hash bucket
+ {
+ tmp1->hashnext = tmp2;
+ if (tmp2 != 0)
+ tmp2->hashprev = tmp1;
+ }
+
+ // Relink elements in list
+
+ tmp1 = curhashelem->listprev;
+ tmp2 = curhashelem->listnext;
+ if (tmp1 == 0) // curhashelem is first in list
+ {
+ firsthashelem = tmp2;
+ if (tmp2 != 0)
+ tmp2->listprev = 0;
+ else // curhashelem is also last in list
+ lasthashelem = 0;
+ }
+ else
+ {
+ tmp1->listnext = tmp2;
+ if (tmp2 != 0)
+ tmp2->listprev = tmp1;
+ else // curhashelem is last in list
+ lasthashelem = tmp1;
+ }
+
+ // finally, with everything being relinked, we can delete curhashelem
+ RTPDelete(curhashelem,GetMemoryManager());
+ curhashelem = tmp2; // Set to next element in list
+ }
+ else
+ return ERR_RTP_KEYHASHTABLE_NOCURRENTELEMENT;
+ return 0;
+}
+
+template<class Key,class Element,class GetIndex,int hashsize>
+inline int RTPKeyHashTable<Key,Element,GetIndex,hashsize>::GotoElement(const Key &k)
+{
+ int index;
+ bool found;
+
+ index = GetIndex::GetIndex(k);
+ if (index >= hashsize)
+ return ERR_RTP_KEYHASHTABLE_FUNCTIONRETURNEDINVALIDHASHINDEX;
+
+ curhashelem = table[index];
+ found = false;
+ while(!found && curhashelem != 0)
+ {
+ if (curhashelem->GetKey() == k)
+ found = true;
+ else
+ curhashelem = curhashelem->hashnext;
+ }
+ if (!found)
+ return ERR_RTP_KEYHASHTABLE_KEYNOTFOUND;
+ return 0;
+}
+
+template<class Key,class Element,class GetIndex,int hashsize>
+inline bool RTPKeyHashTable<Key,Element,GetIndex,hashsize>::HasElement(const Key &k)
+{
+ int index;
+ bool found;
+ HashElement *tmp;
+
+ index = GetIndex::GetIndex(k);
+ if (index >= hashsize)
+ return false;
+
+ tmp = table[index];
+ found = false;
+ while(!found && tmp != 0)
+ {
+ if (tmp->GetKey() == k)
+ found = true;
+ else
+ tmp = tmp->hashnext;
+ }
+ return found;
+}
+
+template<class Key,class Element,class GetIndex,int hashsize>
+inline void RTPKeyHashTable<Key,Element,GetIndex,hashsize>::GotoNextElement()
+{
+ if (curhashelem)
+ curhashelem = curhashelem->listnext;
+}
+
+template<class Key,class Element,class GetIndex,int hashsize>
+inline void RTPKeyHashTable<Key,Element,GetIndex,hashsize>::GotoPreviousElement()
+{
+ if (curhashelem)
+ curhashelem = curhashelem->listprev;
+}
+
+template<class Key,class Element,class GetIndex,int hashsize>
+inline void RTPKeyHashTable<Key,Element,GetIndex,hashsize>::Clear()
+{
+ HashElement *tmp1,*tmp2;
+
+ for (int i = 0 ; i < hashsize ; i++)
+ table[i] = 0;
+
+ tmp1 = firsthashelem;
+ while (tmp1 != 0)
+ {
+ tmp2 = tmp1->listnext;
+ RTPDelete(tmp1,GetMemoryManager());
+ tmp1 = tmp2;
+ }
+ firsthashelem = 0;
+ lasthashelem = 0;
+}
+
+template<class Key,class Element,class GetIndex,int hashsize>
+inline int RTPKeyHashTable<Key,Element,GetIndex,hashsize>::AddElement(const Key &k,const Element &elem)
+{
+ int index;
+ bool found;
+ HashElement *e,*newelem;
+
+ index = GetIndex::GetIndex(k);
+ if (index >= hashsize)
+ return ERR_RTP_KEYHASHTABLE_FUNCTIONRETURNEDINVALIDHASHINDEX;
+
+ e = table[index];
+ found = false;
+ while(!found && e != 0)
+ {
+ if (e->GetKey() == k)
+ found = true;
+ else
+ e = e->hashnext;
+ }
+ if (found)
+ return ERR_RTP_KEYHASHTABLE_KEYALREADYEXISTS;
+
+ // Okay, the key doesn't exist, so we can add the new element in the hash table
+
+ newelem = RTPNew(GetMemoryManager(),memorytype) HashElement(k,elem,index);
+ if (newelem == 0)
+ return ERR_RTP_OUTOFMEM;
+
+ e = table[index];
+ table[index] = newelem;
+ newelem->hashnext = e;
+ if (e != 0)
+ e->hashprev = newelem;
+
+ // Now, we still got to add it to the linked list
+
+ if (firsthashelem == 0)
+ {
+ firsthashelem = newelem;
+ lasthashelem = newelem;
+ }
+ else // there already are some elements in the list
+ {
+ lasthashelem->listnext = newelem;
+ newelem->listprev = lasthashelem;
+ lasthashelem = newelem;
+ }
+ return 0;
+}
+
+template<class Key,class Element,class GetIndex,int hashsize>
+inline int RTPKeyHashTable<Key,Element,GetIndex,hashsize>::DeleteElement(const Key &k)
+{
+ int status;
+
+ status = GotoElement(k);
+ if (status < 0)
+ return status;
+ return DeleteCurrentElement();
+}
+
+#ifdef RTPDEBUG
+template<class Key,class Element,class GetIndex,int hashsize>
+inline void RTPKeyHashTable<Key,Element,GetIndex,hashsize>::Dump()
+{
+ HashElement *e;
+
+ std::cout << "DUMPING TABLE CONTENTS:" << std::endl;
+ for (int i = 0 ; i < hashsize ; i++)
+ {
+ e = table[i];
+ while (e != 0)
+ {
+ e->Dump();
+ e = e->hashnext;
+ }
+ }
+
+ std::cout << "DUMPING LIST CONTENTS:" << std::endl;
+ e = firsthashelem;
+ while (e != 0)
+ {
+ e->Dump();
+ e = e->listnext;
+ }
+}
+#endif // RTPDEBUG
+
+#endif // RTPKEYHASHTABLE_H
diff --git a/src/rtplibraryversion.cpp b/src/rtplibraryversion.cpp
new file mode 100644
index 0000000..a1b15d3
--- /dev/null
+++ b/src/rtplibraryversion.cpp
@@ -0,0 +1,50 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtplibraryversion.h"
+#include "rtpdefines.h"
+
+RTPLibraryVersion RTPLibraryVersion::GetVersion()
+{
+ return RTPLibraryVersion(3,7,1);
+}
+
+std::string RTPLibraryVersion::GetVersionString() const
+{
+ char str[16];
+
+ RTP_SNPRINTF(str,16,"%d.%d.%d",majornr,minornr,debugnr);
+
+ return std::string(str);
+}
+
+
diff --git a/src/rtplibraryversion.h b/src/rtplibraryversion.h
new file mode 100644
index 0000000..927bcf8
--- /dev/null
+++ b/src/rtplibraryversion.h
@@ -0,0 +1,71 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtplibraryversion.h
+ */
+
+#ifndef RTPLIBRARYVERSION_H
+
+#define RTPLIBRARYVERSION_H
+
+#include <string>
+#include <stdio.h>
+
+/**
+ * Used to provide information about the version of the library.
+ */
+class RTPLibraryVersion
+{
+public:
+ /** Returns an instance of RTPLibraryVersion describing the version of the library. */
+ static RTPLibraryVersion GetVersion();
+private:
+ RTPLibraryVersion(int major,int minor,int debug) { majornr = major; minornr = minor; debugnr = debug; }
+public:
+ /** Returns the major version number. */
+ int GetMajorNumber() const { return majornr; }
+
+ /** Returns the minor version number. */
+ int GetMinorNumber() const { return minornr; }
+
+ /** Returns the debug version number. */
+ int GetDebugNumber() const { return debugnr; }
+
+ /** Returns a string describing the library version. */
+ std::string GetVersionString() const;
+private:
+ int debugnr,minornr,majornr;
+};
+
+#endif // RTPLIBRARYVERSION_H
+
diff --git a/src/rtpmemorymanager.h b/src/rtpmemorymanager.h
new file mode 100644
index 0000000..bfc50fa
--- /dev/null
+++ b/src/rtpmemorymanager.h
@@ -0,0 +1,247 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpmemorymanager.h
+ */
+
+#ifndef RTPMEMORYMANAGER_H
+
+#define RTPMEMORYMANAGER_H
+
+#include "rtpconfig.h"
+#include "rtptypes.h"
+
+/** Used to indicate a general kind of memory block. */
+#define RTPMEM_TYPE_OTHER 0
+
+/** Buffer to store an incoming RTP packet. */
+#define RTPMEM_TYPE_BUFFER_RECEIVEDRTPPACKET 1
+
+/** Buffer to store an incoming RTCP packet. */
+#define RTPMEM_TYPE_BUFFER_RECEIVEDRTCPPACKET 2
+
+/** Buffer to store an RTCP APP packet. */
+#define RTPMEM_TYPE_BUFFER_RTCPAPPPACKET 3
+
+/** Buffer to store an RTCP BYE packet. */
+#define RTPMEM_TYPE_BUFFER_RTCPBYEPACKET 4
+
+/** Buffer to store a BYE reason. */
+#define RTPMEM_TYPE_BUFFER_RTCPBYEREASON 5
+
+/** Buffer to store an RTCP compound packet. */
+#define RTPMEM_TYPE_BUFFER_RTCPCOMPOUNDPACKET 6
+
+/** Buffer to store an SDES block. */
+#define RTPMEM_TYPE_BUFFER_RTCPSDESBLOCK 7
+
+/** Buffer to store an RTP packet. */
+#define RTPMEM_TYPE_BUFFER_RTPPACKET 8
+
+/** Buffer used by an RTPPacketBuilder instance. */
+#define RTPMEM_TYPE_BUFFER_RTPPACKETBUILDERBUFFER 9
+
+/** Buffer to store an SDES item. */
+#define RTPMEM_TYPE_BUFFER_SDESITEM 10
+
+/** Hash element used in the accept/ignore table. */
+#define RTPMEM_TYPE_CLASS_ACCEPTIGNOREHASHELEMENT 11
+
+/** Buffer to store a PortInfo instance, used by the UDP over IPv4 and IPv6 transmitters. */
+#define RTPMEM_TYPE_CLASS_ACCEPTIGNOREPORTINFO 12
+
+/** Buffer to store a HashElement instance for the destination hash table. */
+#define RTPMEM_TYPE_CLASS_DESTINATIONLISTHASHELEMENT 13
+
+/** Buffer to store a HashElement instance for the multicast hash table. */
+#define RTPMEM_TYPE_CLASS_MULTICASTHASHELEMENT 14
+
+/** Buffer to store an instance of RTCPAPPPacket. */
+#define RTPMEM_TYPE_CLASS_RTCPAPPPACKET 15
+
+/** Buffer to store an instance of RTCPBYEPacket. */
+#define RTPMEM_TYPE_CLASS_RTCPBYEPACKET 16
+
+/** Buffer to store an instance of RTCPCompoundPacketBuilder. */
+#define RTPMEM_TYPE_CLASS_RTCPCOMPOUNDPACKETBUILDER 17
+
+/** Buffer to store an RTCPReceiverReport instance. */
+#define RTPMEM_TYPE_CLASS_RTCPRECEIVERREPORT 18
+
+/** Buffer to store an instance of RTCPRRPacket. */
+#define RTPMEM_TYPE_CLASS_RTCPRRPACKET 19
+
+/** Buffer to store an instance of RTCPSDESPacket. */
+#define RTPMEM_TYPE_CLASS_RTCPSDESPACKET 20
+
+/** Buffer to store an instance of RTCPSRPacket. */
+#define RTPMEM_TYPE_CLASS_RTCPSRPACKET 21
+
+/** Buffer to store an instance of RTCPUnknownPacket. */
+#define RTPMEM_TYPE_CLASS_RTCPUNKNOWNPACKET 22
+
+/** Buffer to store an instance of an RTPAddress derived class. */
+#define RTPMEM_TYPE_CLASS_RTPADDRESS 23
+
+/** Buffer to store an instance of RTPInternalSourceData. */
+#define RTPMEM_TYPE_CLASS_RTPINTERNALSOURCEDATA 24
+
+/** Buffer to store an RTPPacket instance. */
+#define RTPMEM_TYPE_CLASS_RTPPACKET 25
+
+/** Buffer to store an RTPPollThread instance. */
+#define RTPMEM_TYPE_CLASS_RTPPOLLTHREAD 26
+
+/** Buffer to store an RTPRawPacket instance. */
+#define RTPMEM_TYPE_CLASS_RTPRAWPACKET 27
+
+/** Buffer to store an RTPTransmissionInfo derived class. */
+#define RTPMEM_TYPE_CLASS_RTPTRANSMISSIONINFO 28
+
+/** Buffer to store an RTPTransmitter derived class. */
+#define RTPMEM_TYPE_CLASS_RTPTRANSMITTER 29
+
+/** Buffer to store an SDESPrivateItem instance. */
+#define RTPMEM_TYPE_CLASS_SDESPRIVATEITEM 30
+
+/** Buffer to store an SDESSource instance. */
+#define RTPMEM_TYPE_CLASS_SDESSOURCE 31
+
+/** Buffer to store a HashElement instance for the source table. */
+#define RTPMEM_TYPE_CLASS_SOURCETABLEHASHELEMENT 32
+
+/** A memory manager. */
+class RTPMemoryManager
+{
+public:
+ RTPMemoryManager() { }
+ virtual ~RTPMemoryManager() { }
+
+ /** Called to allocate \c numbytes of memory.
+ * Called to allocate \c numbytes of memory. The \c memtype parameter
+ * indicates what the purpose of the memory block is. Relevant values
+ * can be found in rtpmemorymanager.h . Note that the types starting with
+ * \c RTPMEM_TYPE_CLASS indicate fixed size buffers and that types starting
+ * with \c RTPMEM_TYPE_BUFFER indicate variable size buffers.
+ */
+ virtual void *AllocateBuffer(size_t numbytes, int memtype) = 0;
+
+ /** Frees the previously allocated memory block \c buffer */
+ virtual void FreeBuffer(void *buffer) = 0;
+};
+
+#ifdef RTP_SUPPORT_MEMORYMANAGEMENT
+
+#include <new>
+
+inline void *operator new(size_t numbytes, RTPMemoryManager *mgr, int memtype)
+{
+ if (mgr == 0)
+ return operator new(numbytes);
+ return mgr->AllocateBuffer(numbytes,memtype);
+}
+
+inline void operator delete(void *buffer, RTPMemoryManager *mgr, int memtype)
+{
+ if (mgr == 0)
+ operator delete(buffer);
+ else
+ mgr->FreeBuffer(buffer);
+}
+
+#if defined(WIN32) || defined(_WIN32_WCE)
+#if _MSC_VER >= 1300
+inline void *operator new[](size_t numbytes, RTPMemoryManager *mgr, int memtype)
+{
+ if (mgr == 0)
+ return operator new[](numbytes);
+ return mgr->AllocateBuffer(numbytes,memtype);
+}
+
+inline void operator delete[](void *buffer, RTPMemoryManager *mgr, int memtype)
+{
+ if (mgr == 0)
+ operator delete[](buffer);
+ else
+ mgr->FreeBuffer(buffer);
+}
+#endif // _MSC_VER >= 1300
+#else
+inline void *operator new[](size_t numbytes, RTPMemoryManager *mgr, int memtype)
+{
+ if (mgr == 0)
+ return operator new[](numbytes);
+ return mgr->AllocateBuffer(numbytes,memtype);
+}
+
+inline void operator delete[](void *buffer, RTPMemoryManager *mgr, int memtype)
+{
+ if (mgr == 0)
+ operator delete[](buffer);
+ else
+ mgr->FreeBuffer(buffer);
+}
+#endif // WIN32 || _WIN32_WCE
+
+inline void RTPDeleteByteArray(uint8_t *buf, RTPMemoryManager *mgr)
+{
+ if (mgr == 0)
+ delete [] buf;
+ else
+ mgr->FreeBuffer(buf);
+}
+
+template<class ClassName>
+inline void RTPDelete(ClassName *obj, RTPMemoryManager *mgr)
+{
+ if (mgr == 0)
+ delete obj;
+ else
+ {
+ obj->~ClassName();
+ mgr->FreeBuffer(obj);
+ }
+}
+
+#define RTPNew(a,b) new(a,b)
+
+#else
+
+#define RTPNew(a,b) new
+#define RTPDelete(a,b) delete a
+#define RTPDeleteByteArray(a,b) delete [] a;
+
+#endif // RTP_SUPPORT_MEMORYMANAGEMENT
+
+#endif // RTPMEMORYMANAGER_H
+
diff --git a/src/rtpmemoryobject.h b/src/rtpmemoryobject.h
new file mode 100644
index 0000000..c30e5bd
--- /dev/null
+++ b/src/rtpmemoryobject.h
@@ -0,0 +1,69 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpmemoryobject.h
+ */
+
+#ifndef RTPMEMORYOBJECT_H
+
+#define RTPMEMORYOBJECT_H
+
+#include "rtpconfig.h"
+#include "rtpmemorymanager.h"
+
+class RTPMemoryObject
+{
+protected:
+#ifdef RTP_SUPPORT_MEMORYMANAGEMENT
+ RTPMemoryObject(RTPMemoryManager *memmgr) : mgr(memmgr) { }
+#else
+ RTPMemoryObject(RTPMemoryManager *memmgr) { }
+#endif // RTP_SUPPORT_MEMORYMANAGEMENT
+ virtual ~RTPMemoryObject() { }
+
+#ifdef RTP_SUPPORT_MEMORYMANAGEMENT
+ RTPMemoryManager *GetMemoryManager() const { return mgr; }
+ void SetMemoryManager(RTPMemoryManager *m) { mgr = m; }
+#else
+ RTPMemoryManager *GetMemoryManager() const { return 0; }
+ void SetMemoryManager(RTPMemoryManager *m) { }
+#endif // RTP_SUPPORT_MEMORYMANAGEMENT
+
+#ifdef RTP_SUPPORT_MEMORYMANAGEMENT
+private:
+ RTPMemoryManager *mgr;
+#endif // RTP_SUPPORT_MEMORYMANAGEMENT
+};
+
+#endif // RTPMEMORYOBJECT_H
+
diff --git a/src/rtppacket.cpp b/src/rtppacket.cpp
new file mode 100644
index 0000000..b6d5fda
--- /dev/null
+++ b/src/rtppacket.cpp
@@ -0,0 +1,344 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtppacket.h"
+#include "rtpstructs.h"
+#include "rtpdefines.h"
+#include "rtperrors.h"
+#include "rtprawpacket.h"
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ #include <netinet/in.h>
+#endif // WIN32
+
+#ifdef RTPDEBUG
+ #include <stdio.h>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+void RTPPacket::Clear()
+{
+ hasextension = false;
+ hasmarker = false;
+ numcsrcs = 0;
+ payloadtype = 0;
+ extseqnr = 0;
+ timestamp = 0;
+ ssrc = 0;
+ packet = 0;
+ payload = 0;
+ packetlength = 0;
+ payloadlength = 0;
+ extid = 0;
+ extension = 0;
+ extensionlength = 0;
+ error = 0;
+ externalbuffer = false;
+}
+
+RTPPacket::RTPPacket(RTPRawPacket &rawpack,RTPMemoryManager *mgr) : RTPMemoryObject(mgr),receivetime(rawpack.GetReceiveTime())
+{
+ Clear();
+ error = ParseRawPacket(rawpack);
+}
+
+RTPPacket::RTPPacket(uint8_t payloadtype,const void *payloaddata,size_t payloadlen,uint16_t seqnr,
+ uint32_t timestamp,uint32_t ssrc,bool gotmarker,uint8_t numcsrcs,const uint32_t *csrcs,
+ bool gotextension,uint16_t extensionid,uint16_t extensionlen_numwords,const void *extensiondata,
+ size_t maxpacksize, RTPMemoryManager *mgr) : RTPMemoryObject(mgr),receivetime(0,0)
+{
+ Clear();
+ error = BuildPacket(payloadtype,payloaddata,payloadlen,seqnr,timestamp,ssrc,gotmarker,numcsrcs,
+ csrcs,gotextension,extensionid,extensionlen_numwords,extensiondata,0,maxpacksize);
+}
+
+RTPPacket::RTPPacket(uint8_t payloadtype,const void *payloaddata,size_t payloadlen,uint16_t seqnr,
+ uint32_t timestamp,uint32_t ssrc,bool gotmarker,uint8_t numcsrcs,const uint32_t *csrcs,
+ bool gotextension,uint16_t extensionid,uint16_t extensionlen_numwords,const void *extensiondata,
+ void *buffer,size_t buffersize, RTPMemoryManager *mgr) : RTPMemoryObject(mgr),receivetime(0,0)
+{
+ Clear();
+ if (buffer == 0)
+ error = ERR_RTP_PACKET_EXTERNALBUFFERNULL;
+ else if (buffersize <= 0)
+ error = ERR_RTP_PACKET_ILLEGALBUFFERSIZE;
+ else
+ error = BuildPacket(payloadtype,payloaddata,payloadlen,seqnr,timestamp,ssrc,gotmarker,numcsrcs,
+ csrcs,gotextension,extensionid,extensionlen_numwords,extensiondata,buffer,buffersize);
+}
+
+int RTPPacket::ParseRawPacket(RTPRawPacket &rawpack)
+{
+ uint8_t *packetbytes;
+ size_t packetlen;
+ uint8_t payloadtype;
+ RTPHeader *rtpheader;
+ bool marker;
+ int csrccount;
+ bool hasextension;
+ int payloadoffset,payloadlength;
+ int numpadbytes;
+ RTPExtensionHeader *rtpextheader;
+ uint16_t exthdrlen;
+
+ if (!rawpack.IsRTP()) // If we didn't receive it on the RTP port, we'll ignore it
+ return ERR_RTP_PACKET_INVALIDPACKET;
+
+ // The length should be at least the size of the RTP header
+ packetlen = rawpack.GetDataLength();
+ if (packetlen < sizeof(RTPHeader))
+ return ERR_RTP_PACKET_INVALIDPACKET;
+
+ packetbytes = (uint8_t *)rawpack.GetData();
+ rtpheader = (RTPHeader *)packetbytes;
+
+ // The version number should be correct
+ if (rtpheader->version != RTP_VERSION)
+ return ERR_RTP_PACKET_INVALIDPACKET;
+
+ // We'll check if this is possibly a RTCP packet. For this to be possible
+ // the marker bit and payload type combined should be either an SR or RR
+ // identifier
+ marker = (rtpheader->marker == 0)?false:true;
+ payloadtype = rtpheader->payloadtype;
+ if (marker)
+ {
+ if (payloadtype == (RTP_RTCPTYPE_SR & 127)) // don't check high bit (this was the marker!!)
+ return ERR_RTP_PACKET_INVALIDPACKET;
+ if (payloadtype == (RTP_RTCPTYPE_RR & 127))
+ return ERR_RTP_PACKET_INVALIDPACKET;
+ }
+
+ csrccount = rtpheader->csrccount;
+ payloadoffset = sizeof(RTPHeader)+(int)(csrccount*sizeof(uint32_t));
+
+ if (rtpheader->padding) // adjust payload length to take padding into account
+ {
+ numpadbytes = (int)packetbytes[packetlen-1]; // last byte contains number of padding bytes
+ if (numpadbytes <= 0)
+ return ERR_RTP_PACKET_INVALIDPACKET;
+ }
+ else
+ numpadbytes = 0;
+
+ hasextension = (rtpheader->extension == 0)?false:true;
+ if (hasextension) // got header extension
+ {
+ rtpextheader = (RTPExtensionHeader *)(packetbytes+payloadoffset);
+ payloadoffset += sizeof(RTPExtensionHeader);
+ exthdrlen = ntohs(rtpextheader->length);
+ payloadoffset += ((int)exthdrlen)*sizeof(uint32_t);
+ }
+ else
+ {
+ rtpextheader = 0;
+ exthdrlen = 0;
+ }
+
+ payloadlength = packetlen-numpadbytes-payloadoffset;
+ if (payloadlength < 0)
+ return ERR_RTP_PACKET_INVALIDPACKET;
+
+ // Now, we've got a valid packet, so we can create a new instance of RTPPacket
+ // and fill in the members
+
+ RTPPacket::hasextension = hasextension;
+ if (hasextension)
+ {
+ RTPPacket::extid = ntohs(rtpextheader->extid);
+ RTPPacket::extensionlength = ((int)ntohs(rtpextheader->length))*sizeof(uint32_t);
+ RTPPacket::extension = ((uint8_t *)rtpextheader)+sizeof(RTPExtensionHeader);
+ }
+
+ RTPPacket::hasmarker = marker;
+ RTPPacket::numcsrcs = csrccount;
+ RTPPacket::payloadtype = payloadtype;
+
+ // Note: we don't fill in the EXTENDED sequence number here, since we
+ // don't have information about the source here. We just fill in the low
+ // 16 bits
+ RTPPacket::extseqnr = (uint32_t)ntohs(rtpheader->sequencenumber);
+
+ RTPPacket::timestamp = ntohl(rtpheader->timestamp);
+ RTPPacket::ssrc = ntohl(rtpheader->ssrc);
+ RTPPacket::packet = packetbytes;
+ RTPPacket::payload = packetbytes+payloadoffset;
+ RTPPacket::packetlength = packetlen;
+ RTPPacket::payloadlength = payloadlength;
+
+ // We'll zero the data of the raw packet, since we're using it here now!
+ rawpack.ZeroData();
+
+ return 0;
+}
+
+uint32_t RTPPacket::GetCSRC(int num) const
+{
+ if (num >= numcsrcs)
+ return 0;
+
+ uint8_t *csrcpos;
+ uint32_t *csrcval_nbo;
+ uint32_t csrcval_hbo;
+
+ csrcpos = packet+sizeof(RTPHeader)+num*sizeof(uint32_t);
+ csrcval_nbo = (uint32_t *)csrcpos;
+ csrcval_hbo = ntohl(*csrcval_nbo);
+ return csrcval_hbo;
+}
+
+int RTPPacket::BuildPacket(uint8_t payloadtype,const void *payloaddata,size_t payloadlen,uint16_t seqnr,
+ uint32_t timestamp,uint32_t ssrc,bool gotmarker,uint8_t numcsrcs,const uint32_t *csrcs,
+ bool gotextension,uint16_t extensionid,uint16_t extensionlen_numwords,const void *extensiondata,
+ void *buffer,size_t maxsize)
+{
+ if (numcsrcs > RTP_MAXCSRCS)
+ return ERR_RTP_PACKET_TOOMANYCSRCS;
+
+ if (payloadtype > 127) // high bit should not be used
+ return ERR_RTP_PACKET_BADPAYLOADTYPE;
+ if (payloadtype == 72 || payloadtype == 73) // could cause confusion with rtcp types
+ return ERR_RTP_PACKET_BADPAYLOADTYPE;
+
+ packetlength = sizeof(RTPHeader);
+ packetlength += sizeof(uint32_t)*((size_t)numcsrcs);
+ if (gotextension)
+ {
+ packetlength += sizeof(RTPExtensionHeader);
+ packetlength += sizeof(uint32_t)*((size_t)extensionlen_numwords);
+ }
+ packetlength += payloadlen;
+
+ if (maxsize > 0 && packetlength > maxsize)
+ {
+ packetlength = 0;
+ return ERR_RTP_PACKET_DATAEXCEEDSMAXSIZE;
+ }
+
+ // Ok, now we'll just fill in...
+
+ RTPHeader *rtphdr;
+
+ if (buffer == 0)
+ {
+ packet = RTPNew(GetMemoryManager(),RTPMEM_TYPE_BUFFER_RTPPACKET) uint8_t [packetlength];
+ if (packet == 0)
+ {
+ packetlength = 0;
+ return ERR_RTP_OUTOFMEM;
+ }
+ externalbuffer = false;
+ }
+ else
+ {
+ packet = (uint8_t *)buffer;
+ externalbuffer = true;
+ }
+
+ RTPPacket::hasmarker = gotmarker;
+ RTPPacket::hasextension = gotextension;
+ RTPPacket::numcsrcs = numcsrcs;
+ RTPPacket::payloadtype = payloadtype;
+ RTPPacket::extseqnr = (uint32_t)seqnr;
+ RTPPacket::timestamp = timestamp;
+ RTPPacket::ssrc = ssrc;
+ RTPPacket::payloadlength = payloadlen;
+ RTPPacket::extid = extensionid;
+ RTPPacket::extensionlength = ((size_t)extensionlen_numwords)*sizeof(uint32_t);
+
+ rtphdr = (RTPHeader *)packet;
+ rtphdr->version = RTP_VERSION;
+ rtphdr->padding = 0;
+ if (gotmarker)
+ rtphdr->marker = 1;
+ else
+ rtphdr->marker = 0;
+ if (gotextension)
+ rtphdr->extension = 1;
+ else
+ rtphdr->extension = 0;
+ rtphdr->csrccount = numcsrcs;
+ rtphdr->payloadtype = payloadtype&127; // make sure high bit isn't set
+ rtphdr->sequencenumber = htons(seqnr);
+ rtphdr->timestamp = htonl(timestamp);
+ rtphdr->ssrc = htonl(ssrc);
+
+ uint32_t *curcsrc;
+ int i;
+
+ curcsrc = (uint32_t *)(packet+sizeof(RTPHeader));
+ for (i = 0 ; i < numcsrcs ; i++,curcsrc++)
+ *curcsrc = htonl(csrcs[i]);
+
+ payload = packet+sizeof(RTPHeader)+((size_t)numcsrcs)*sizeof(uint32_t);
+ if (gotextension)
+ {
+ RTPExtensionHeader *rtpexthdr = (RTPExtensionHeader *)payload;
+
+ rtpexthdr->extid = htons(extensionid);
+ rtpexthdr->length = htons((uint16_t)extensionlen_numwords);
+
+ payload += sizeof(RTPExtensionHeader);
+ memcpy(payload,extensiondata,RTPPacket::extensionlength);
+
+ payload += RTPPacket::extensionlength;
+ }
+ memcpy(payload,payloaddata,payloadlen);
+ return 0;
+}
+
+#ifdef RTPDEBUG
+void RTPPacket::Dump()
+{
+ int i;
+
+ printf("Payload type: %d\n",(int)GetPayloadType());
+ printf("Extended sequence number: 0x%08x\n",GetExtendedSequenceNumber());
+ printf("Timestamp: 0x%08x\n",GetTimestamp());
+ printf("SSRC: 0x%08x\n",GetSSRC());
+ printf("Marker: %s\n",HasMarker()?"yes":"no");
+ printf("CSRC count: %d\n",GetCSRCCount());
+ for (i = 0 ; i < GetCSRCCount() ; i++)
+ printf(" CSRC[%02d]: 0x%08x\n",i,GetCSRC(i));
+ printf("Payload: %s\n",GetPayloadData());
+ printf("Payload length: %d\n",GetPayloadLength());
+ printf("Packet length: %d\n",GetPacketLength());
+ printf("Extension: %s\n",HasExtension()?"yes":"no");
+ if (HasExtension())
+ {
+ printf(" Extension ID: 0x%04x\n",GetExtensionID());
+ printf(" Extension data: %s\n",GetExtensionData());
+ printf(" Extension length: %d\n",GetExtensionLength());
+ }
+}
+#endif // RTPDEBUG
+
diff --git a/src/rtppacket.h b/src/rtppacket.h
new file mode 100644
index 0000000..9046ec2
--- /dev/null
+++ b/src/rtppacket.h
@@ -0,0 +1,178 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtppacket.h
+ */
+
+#ifndef RTPPACKET_H
+
+#define RTPPACKET_H
+
+#include "rtpconfig.h"
+#include "rtptypes.h"
+#include "rtptimeutilities.h"
+#include "rtpmemoryobject.h"
+
+class RTPRawPacket;
+
+/** Represents an RTP Packet.
+ * The RTPPacket class can be used to parse a RTPRawPacket instance if it represents RTP data.
+ * The class can also be used to create a new RTP packet according to the parameters specified by
+ * the user.
+ */
+class RTPPacket : public RTPMemoryObject
+{
+public:
+ /** Creates an RTPPacket instance based upon the data in \c rawpack, optionally installing a memory manager.
+ * Creates an RTPPacket instance based upon the data in \c rawpack, optionally installing a memory manager.
+ * If successful, the data is moved from the raw packet to the RTPPacket instance.
+ */
+ RTPPacket(RTPRawPacket &rawpack,RTPMemoryManager *mgr = 0);
+
+ /** Creates a new buffer for an RTP packet and fills in the fields according to the specified parameters.
+ * Creates a new buffer for an RTP packet and fills in the fields according to the specified parameters.
+ * If \c maxpacksize is not equal to zero, an error is generated if the total packet size would exceed
+ * \c maxpacksize. The arguments of the constructor are self-explanatory. Note that the size of a header
+ * extension is specified in a number of 32-bit words. A memory manager can be installed.
+ */
+ RTPPacket(uint8_t payloadtype,const void *payloaddata,size_t payloadlen,uint16_t seqnr,
+ uint32_t timestamp,uint32_t ssrc,bool gotmarker,uint8_t numcsrcs,const uint32_t *csrcs,
+ bool gotextension,uint16_t extensionid,uint16_t extensionlen_numwords,const void *extensiondata,
+ size_t maxpacksize, RTPMemoryManager *mgr = 0);
+
+ /** This constructor is similar to the other constructor, but here data is stored in an external buffer
+ * \c buffer with size \c buffersize. */
+ RTPPacket(uint8_t payloadtype,const void *payloaddata,size_t payloadlen,uint16_t seqnr,
+ uint32_t timestamp,uint32_t ssrc,bool gotmarker,uint8_t numcsrcs,const uint32_t *csrcs,
+ bool gotextension,uint16_t extensionid,uint16_t extensionlen_numwords,const void *extensiondata,
+ void *buffer,size_t buffersize,RTPMemoryManager *mgr = 0);
+
+ virtual ~RTPPacket() { if (packet && !externalbuffer) RTPDeleteByteArray(packet,GetMemoryManager()); }
+
+ /** If an error occurred in one of the constructors, this function returns the error code. */
+ int GetCreationError() const { return error; }
+
+ /** Returns \c true if the RTP packet has a header extension and \c false otherwise. */
+ bool HasExtension() const { return hasextension; }
+
+ /** Returns \c true if the marker bit was set and \c false otherwise. */
+ bool HasMarker() const { return hasmarker; }
+
+ /** Returns the number of CSRCs contained in this packet. */
+ int GetCSRCCount() const { return numcsrcs; }
+
+ /** Returns a specific CSRC identifier.
+ * Returns a specific CSRC identifier. The parameter \c num can go from 0 to GetCSRCCount()-1.
+ */
+ uint32_t GetCSRC(int num) const;
+
+ /** Returns the payload type of the packet. */
+ uint8_t GetPayloadType() const { return payloadtype; }
+
+ /** Returns the extended sequence number of the packet.
+ * Returns the extended sequence number of the packet. When the packet is just received,
+ * only the low $16$ bits will be set. The high 16 bits can be filled in later.
+ */
+ uint32_t GetExtendedSequenceNumber() const { return extseqnr; }
+
+ /** Returns the sequence number of this packet. */
+ uint16_t GetSequenceNumber() const { return (uint16_t)(extseqnr&0x0000FFFF); }
+
+ /** Sets the extended sequence number of this packet to \c seq. */
+ void SetExtendedSequenceNumber(uint32_t seq) { extseqnr = seq; }
+
+ /** Returns the timestamp of this packet. */
+ uint32_t GetTimestamp() const { return timestamp; }
+
+ /** Returns the SSRC identifier stored in this packet. */
+ uint32_t GetSSRC() const { return ssrc; }
+
+ /** Returns a pointer to the data of the entire packet. */
+ uint8_t *GetPacketData() const { return packet; }
+
+ /** Returns a pointer to the actual payload data. */
+ uint8_t *GetPayloadData() const { return payload; }
+
+ /** Returns the length of the entire packet. */
+ size_t GetPacketLength() const { return packetlength; }
+
+ /** Returns the payload length. */
+ size_t GetPayloadLength() const { return payloadlength; }
+
+ /** If a header extension is present, this function returns the extension identifier. */
+ uint16_t GetExtensionID() const { return extid; }
+
+ /** Returns the length of the header extension data. */
+ uint8_t *GetExtensionData() const { return extension; }
+
+ /** Returns the length of the header extension data. */
+ size_t GetExtensionLength() const { return extensionlength; }
+#ifdef RTPDEBUG
+ void Dump();
+#endif // RTPDEBUG
+
+ /** Returns the time at which this packet was received.
+ * When an RTPPacket instance is created from an RTPRawPacket instance, the raw packet's
+ * reception time is stored in the RTPPacket instance. This function then retrieves that
+ * time.
+ */
+ RTPTime GetReceiveTime() const { return receivetime; }
+private:
+ void Clear();
+ int ParseRawPacket(RTPRawPacket &rawpack);
+ int BuildPacket(uint8_t payloadtype,const void *payloaddata,size_t payloadlen,uint16_t seqnr,
+ uint32_t timestamp,uint32_t ssrc,bool gotmarker,uint8_t numcsrcs,const uint32_t *csrcs,
+ bool gotextension,uint16_t extensionid,uint16_t extensionlen_numwords,const void *extensiondata,
+ void *buffer,size_t maxsize);
+
+ int error;
+
+ bool hasextension,hasmarker;
+ int numcsrcs;
+
+ uint8_t payloadtype;
+ uint32_t extseqnr,timestamp,ssrc;
+ uint8_t *packet,*payload;
+ size_t packetlength,payloadlength;
+
+ uint16_t extid;
+ uint8_t *extension;
+ size_t extensionlength;
+
+ bool externalbuffer;
+
+ RTPTime receivetime;
+};
+
+#endif // RTPPACKET_H
+
diff --git a/src/rtppacketbuilder.cpp b/src/rtppacketbuilder.cpp
new file mode 100644
index 0000000..76dca01
--- /dev/null
+++ b/src/rtppacketbuilder.cpp
@@ -0,0 +1,268 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtppacketbuilder.h"
+#include "rtperrors.h"
+#include "rtppacket.h"
+#include "rtpsources.h"
+#include <time.h>
+#include <stdlib.h>
+#ifdef RTPDEBUG
+ #include <iostream>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+RTPPacketBuilder::RTPPacketBuilder(RTPMemoryManager *mgr) : RTPMemoryObject(mgr),lastwallclocktime(0,0)
+{
+ init = false;
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ timeinit.Dummy();
+#endif // WIN32 || _WIN32_WCE
+}
+
+RTPPacketBuilder::~RTPPacketBuilder()
+{
+ Destroy();
+}
+
+int RTPPacketBuilder::Init(size_t max)
+{
+ if (init)
+ return ERR_RTP_PACKBUILD_ALREADYINIT;
+ if (max <= 0)
+ return ERR_RTP_PACKBUILD_INVALIDMAXPACKETSIZE;
+
+ maxpacksize = max;
+ buffer = RTPNew(GetMemoryManager(),RTPMEM_TYPE_BUFFER_RTPPACKETBUILDERBUFFER) uint8_t [max];
+ if (buffer == 0)
+ return ERR_RTP_OUTOFMEM;
+ packetlength = 0;
+
+ CreateNewSSRC();
+
+ deftsset = false;
+ defptset = false;
+ defmarkset = false;
+
+ numcsrcs = 0;
+
+ init = true;
+ return 0;
+}
+
+void RTPPacketBuilder::Destroy()
+{
+ if (!init)
+ return;
+ RTPDeleteByteArray(buffer,GetMemoryManager());
+ init = false;
+}
+
+int RTPPacketBuilder::SetMaximumPacketSize(size_t max)
+{
+ uint8_t *newbuf;
+
+ if (max <= 0)
+ return ERR_RTP_PACKBUILD_INVALIDMAXPACKETSIZE;
+ newbuf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_BUFFER_RTPPACKETBUILDERBUFFER) uint8_t[max];
+ if (newbuf == 0)
+ return ERR_RTP_OUTOFMEM;
+
+ RTPDeleteByteArray(buffer,GetMemoryManager());
+ buffer = newbuf;
+ maxpacksize = max;
+ return 0;
+}
+
+int RTPPacketBuilder::AddCSRC(uint32_t csrc)
+{
+ if (!init)
+ return ERR_RTP_PACKBUILD_NOTINIT;
+ if (numcsrcs >= RTP_MAXCSRCS)
+ return ERR_RTP_PACKBUILD_CSRCLISTFULL;
+
+ int i;
+
+ for (i = 0 ; i < numcsrcs ; i++)
+ {
+ if (csrcs[i] == csrc)
+ return ERR_RTP_PACKBUILD_CSRCALREADYINLIST;
+ }
+ csrcs[numcsrcs] = csrc;
+ numcsrcs++;
+ return 0;
+}
+
+int RTPPacketBuilder::DeleteCSRC(uint32_t csrc)
+{
+ if (!init)
+ return ERR_RTP_PACKBUILD_NOTINIT;
+
+ int i = 0;
+ bool found = false;
+
+ while (!found && i < numcsrcs)
+ {
+ if (csrcs[i] == csrc)
+ found = true;
+ else
+ i++;
+ }
+
+ if (!found)
+ return ERR_RTP_PACKBUILD_CSRCNOTINLIST;
+
+ // move the last csrc in the place of the deleted one
+ numcsrcs--;
+ if (numcsrcs > 0 && numcsrcs != i)
+ csrcs[i] = csrcs[numcsrcs];
+ return 0;
+}
+
+void RTPPacketBuilder::ClearCSRCList()
+{
+ if (!init)
+ return;
+ numcsrcs = 0;
+}
+
+uint32_t RTPPacketBuilder::CreateNewSSRC()
+{
+ ssrc = rtprnd.GetRandom32();
+ timestamp = rtprnd.GetRandom32();
+ seqnr = rtprnd.GetRandom16();
+
+ // p 38: the count SHOULD be reset if the sender changes its SSRC identifier
+ numpayloadbytes = 0;
+ numpackets = 0;
+ return ssrc;
+}
+
+uint32_t RTPPacketBuilder::CreateNewSSRC(RTPSources &sources)
+{
+ bool found;
+
+ do
+ {
+ ssrc = rtprnd.GetRandom32();
+ found = sources.GotEntry(ssrc);
+ } while (found);
+
+ timestamp = rtprnd.GetRandom32();
+ seqnr = rtprnd.GetRandom16();
+
+ // p 38: the count SHOULD be reset if the sender changes its SSRC identifier
+ numpayloadbytes = 0;
+ numpackets = 0;
+ return ssrc;
+}
+
+int RTPPacketBuilder::BuildPacket(const void *data,size_t len)
+{
+ if (!init)
+ return ERR_RTP_PACKBUILD_NOTINIT;
+ if (!defptset)
+ return ERR_RTP_PACKBUILD_DEFAULTPAYLOADTYPENOTSET;
+ if (!defmarkset)
+ return ERR_RTP_PACKBUILD_DEFAULTMARKNOTSET;
+ if (!deftsset)
+ return ERR_RTP_PACKBUILD_DEFAULTTSINCNOTSET;
+ return PrivateBuildPacket(data,len,defaultpayloadtype,defaultmark,defaulttimestampinc,false);
+}
+
+int RTPPacketBuilder::BuildPacket(const void *data,size_t len,
+ uint8_t pt,bool mark,uint32_t timestampinc)
+{
+ if (!init)
+ return ERR_RTP_PACKBUILD_NOTINIT;
+ return PrivateBuildPacket(data,len,pt,mark,timestampinc,false);
+}
+
+int RTPPacketBuilder::BuildPacketEx(const void *data,size_t len,
+ uint16_t hdrextID,const void *hdrextdata,size_t numhdrextwords)
+{
+ if (!init)
+ return ERR_RTP_PACKBUILD_NOTINIT;
+ if (!defptset)
+ return ERR_RTP_PACKBUILD_DEFAULTPAYLOADTYPENOTSET;
+ if (!defmarkset)
+ return ERR_RTP_PACKBUILD_DEFAULTMARKNOTSET;
+ if (!deftsset)
+ return ERR_RTP_PACKBUILD_DEFAULTTSINCNOTSET;
+ return PrivateBuildPacket(data,len,defaultpayloadtype,defaultmark,defaulttimestampinc,true,hdrextID,hdrextdata,numhdrextwords);
+}
+
+int RTPPacketBuilder::BuildPacketEx(const void *data,size_t len,
+ uint8_t pt,bool mark,uint32_t timestampinc,
+ uint16_t hdrextID,const void *hdrextdata,size_t numhdrextwords)
+{
+ if (!init)
+ return ERR_RTP_PACKBUILD_NOTINIT;
+ return PrivateBuildPacket(data,len,pt,mark,timestampinc,true,hdrextID,hdrextdata,numhdrextwords);
+
+}
+
+int RTPPacketBuilder::PrivateBuildPacket(const void *data,size_t len,
+ uint8_t pt,bool mark,uint32_t timestampinc,bool gotextension,
+ uint16_t hdrextID,const void *hdrextdata,size_t numhdrextwords)
+{
+ RTPPacket p(pt,data,len,seqnr,timestamp,ssrc,mark,numcsrcs,csrcs,gotextension,hdrextID,
+ (uint16_t)numhdrextwords,hdrextdata,buffer,maxpacksize,GetMemoryManager());
+ int status = p.GetCreationError();
+
+ if (status < 0)
+ return status;
+ packetlength = p.GetPacketLength();
+
+ if (numpackets == 0) // first packet
+ {
+ lastwallclocktime = RTPTime::CurrentTime();
+ lastrtptimestamp = timestamp;
+ prevrtptimestamp = timestamp;
+ }
+ else if (timestamp != prevrtptimestamp)
+ {
+ lastwallclocktime = RTPTime::CurrentTime();
+ lastrtptimestamp = timestamp;
+ prevrtptimestamp = timestamp;
+ }
+
+ numpayloadbytes += (uint32_t)p.GetPayloadLength();
+ numpackets++;
+ timestamp += timestampinc;
+ seqnr++;
+
+ return 0;
+}
+
+
diff --git a/src/rtppacketbuilder.h b/src/rtppacketbuilder.h
new file mode 100644
index 0000000..bb34164
--- /dev/null
+++ b/src/rtppacketbuilder.h
@@ -0,0 +1,261 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtppacketbuilder.h
+ */
+
+#ifndef RTPPACKETBUILDER_H
+
+#define RTPPACKETBUILDER_H
+
+#include "rtpconfig.h"
+#include "rtperrors.h"
+#include "rtpdefines.h"
+#include "rtprandom.h"
+#include "rtptimeutilities.h"
+#include "rtptypes.h"
+#include "rtpmemoryobject.h"
+
+class RTPSources;
+
+/** This class can be used to build RTP packets and is a bit more high-level than the RTPPacket
+ * class: it generates an SSRC identifier, keeps track of timestamp and sequence number etc.
+ */
+class RTPPacketBuilder : public RTPMemoryObject
+{
+public:
+ /** Constructs an instance, optionally installing a memory manager. */
+ RTPPacketBuilder(RTPMemoryManager *mgr = 0);
+ ~RTPPacketBuilder();
+
+ /** Initializes the builder to only allow packets with a size below \c maxpacksize. */
+ int Init(size_t maxpacksize);
+
+ /** Cleans up the builder. */
+ void Destroy();
+
+ /** Returns the number of packets which have been created with the current SSRC identifier. */
+ uint32_t GetPacketCount() { if (!init) return 0; return numpackets; }
+
+ /** Returns the number of payload octets which have been generated with this SSRC identifier. */
+ uint32_t GetPayloadOctetCount() { if (!init) return 0; return numpayloadbytes; }
+
+ /** Sets the maximum allowed packet size to \c maxpacksize. */
+ int SetMaximumPacketSize(size_t maxpacksize);
+
+ /** Adds a CSRC to the CSRC list which will be stored in the RTP packets. */
+ int AddCSRC(uint32_t csrc);
+
+ /** Deletes a CSRC from the list which will be stored in the RTP packets. */
+ int DeleteCSRC(uint32_t csrc);
+
+ /** Clears the CSRC list. */
+ void ClearCSRCList();
+
+ /** Builds a packet with payload \c data and payload length \c len.
+ * Builds a packet with payload \c data and payload length \c len. The payload type, marker
+ * and timestamp increment used will be those that have been set using the \c SetDefault
+ * functions below.
+ */
+ int BuildPacket(const void *data,size_t len);
+
+ /** Builds a packet with payload \c data and payload length \c len.
+ * Builds a packet with payload \c data and payload length \c len. The payload type will be
+ * set to \c pt, the marker bit to \c mark and after building this packet, the timestamp will
+ * be incremented with \c timestamp.
+ */
+ int BuildPacket(const void *data,size_t len,
+ uint8_t pt,bool mark,uint32_t timestampinc);
+
+ /** Builds a packet with payload \c data and payload length \c len.
+ * Builds a packet with payload \c data and payload length \c len. The payload type, marker
+ * and timestamp increment used will be those that have been set using the \c SetDefault
+ * functions below. This packet will also contain an RTP header extension with identifier
+ * \c hdrextID and data \c hdrextdata. The length of the header extension data is given by
+ * \c numhdrextwords which expresses the length in a number of 32-bit words.
+ */
+ int BuildPacketEx(const void *data,size_t len,
+ uint16_t hdrextID,const void *hdrextdata,size_t numhdrextwords);
+
+ /** Builds a packet with payload \c data and payload length \c len.
+ * Builds a packet with payload \c data and payload length \c len. The payload type will be set
+ * to \c pt, the marker bit to \c mark and after building this packet, the timestamp will
+ * be incremented with \c timestamp. This packet will also contain an RTP header extension
+ * with identifier \c hdrextID and data \c hdrextdata. The length of the header extension
+ * data is given by \c numhdrextwords which expresses the length in a number of 32-bit words.
+ */
+ int BuildPacketEx(const void *data,size_t len,
+ uint8_t pt,bool mark,uint32_t timestampinc,
+ uint16_t hdrextID,const void *hdrextdata,size_t numhdrextwords);
+
+ /** Returns a pointer to the last built RTP packet data. */
+ uint8_t *GetPacket() { if (!init) return 0; return buffer; }
+
+ /** Returns the size of the last built RTP packet. */
+ size_t GetPacketLength() { if (!init) return 0; return packetlength; }
+
+ /** Sets the default payload type to \c pt. */
+ int SetDefaultPayloadType(uint8_t pt);
+
+ /** Sets the default marker bit to \c m. */
+ int SetDefaultMark(bool m);
+
+ /** Sets the default timestamp increment to \c timestampinc. */
+ int SetDefaultTimestampIncrement(uint32_t timestampinc);
+
+ /** This function increments the timestamp with the amount given by \c inc.
+ * This function increments the timestamp with the amount given by \c inc. This can be useful
+ * if, for example, a packet was not sent because it contained only silence. Then, this function
+ * should be called to increment the timestamp with the appropriate amount so that the next packets
+ * will still be played at the correct time at other hosts.
+ */
+ int IncrementTimestamp(uint32_t inc);
+
+ /** This function increments the timestamp with the amount given set by the SetDefaultTimestampIncrement
+ * member function.
+ * This function increments the timestamp with the amount given set by the SetDefaultTimestampIncrement
+ * member function. This can be useful if, for example, a packet was not sent because it contained only silence.
+ * Then, this function should be called to increment the timestamp with the appropriate amount so that the next
+ * packets will still be played at the correct time at other hosts.
+ */
+ int IncrementTimestampDefault();
+
+ /** Creates a new SSRC to be used in generated packets.
+ * Creates a new SSRC to be used in generated packets. This will also generate new timestamp and
+ * sequence number offsets.
+ */
+ uint32_t CreateNewSSRC();
+
+ /** Creates a new SSRC to be used in generated packets.
+ * Creates a new SSRC to be used in generated packets. This will also generate new timestamp and
+ * sequence number offsets. The source table \c sources is used to make sure that the chosen SSRC
+ * isn't used by another participant yet.
+ */
+ uint32_t CreateNewSSRC(RTPSources &sources);
+
+ /** Returns the current SSRC identifier. */
+ uint32_t GetSSRC() const { if (!init) return 0; return ssrc; }
+
+ /** Returns the current RTP timestamp. */
+ uint32_t GetTimestamp() const { if (!init) return 0; return timestamp; }
+
+ /** Returns the current sequence number. */
+ uint16_t GetSequenceNumber() const { if (!init) return 0; return seqnr; }
+
+ /** Returns the time at which a packet was generated.
+ * Returns the time at which a packet was generated. This is not necessarily the time at which
+ * the last RTP packet was generated: if the timestamp increment was zero, the time is not updated.
+ */
+ RTPTime GetPacketTime() const { if (!init) return RTPTime(0,0); return lastwallclocktime; }
+
+ /** Returns the RTP timestamp which corresponds to the time returned by the previous function. */
+ uint32_t GetPacketTimestamp() const { if (!init) return 0; return lastrtptimestamp; }
+private:
+ int PrivateBuildPacket(const void *data,size_t len,
+ uint8_t pt,bool mark,uint32_t timestampinc,bool gotextension,
+ uint16_t hdrextID = 0,const void *hdrextdata = 0,size_t numhdrextwords = 0);
+
+ RTPRandom rtprnd;
+ size_t maxpacksize;
+ uint8_t *buffer;
+ size_t packetlength;
+
+ uint32_t numpayloadbytes;
+ uint32_t numpackets;
+ bool init;
+
+ uint32_t ssrc;
+ uint32_t timestamp;
+ uint16_t seqnr;
+
+ uint32_t defaulttimestampinc;
+ uint8_t defaultpayloadtype;
+ bool defaultmark;
+
+ bool deftsset,defptset,defmarkset;
+
+ uint32_t csrcs[RTP_MAXCSRCS];
+ int numcsrcs;
+
+ RTPTime lastwallclocktime;
+ uint32_t lastrtptimestamp;
+ uint32_t prevrtptimestamp;
+};
+
+inline int RTPPacketBuilder::SetDefaultPayloadType(uint8_t pt)
+{
+ if (!init)
+ return ERR_RTP_PACKBUILD_NOTINIT;
+ defptset = true;
+ defaultpayloadtype = pt;
+ return 0;
+}
+
+inline int RTPPacketBuilder::SetDefaultMark(bool m)
+{
+ if (!init)
+ return ERR_RTP_PACKBUILD_NOTINIT;
+ defmarkset = true;
+ defaultmark = m;
+ return 0;
+}
+
+inline int RTPPacketBuilder::SetDefaultTimestampIncrement(uint32_t timestampinc)
+{
+ if (!init)
+ return ERR_RTP_PACKBUILD_NOTINIT;
+ deftsset = true;
+ defaulttimestampinc = timestampinc;
+ return 0;
+}
+
+inline int RTPPacketBuilder::IncrementTimestamp(uint32_t inc)
+{
+ if (!init)
+ return ERR_RTP_PACKBUILD_NOTINIT;
+ timestamp += inc;
+ return 0;
+}
+
+inline int RTPPacketBuilder::IncrementTimestampDefault()
+{
+ if (!init)
+ return ERR_RTP_PACKBUILD_NOTINIT;
+ if (!deftsset)
+ return ERR_RTP_PACKBUILD_DEFAULTTSINCNOTSET;
+ timestamp += defaulttimestampinc;
+ return 0;
+}
+
+#endif // RTPPACKETBUILDER_H
+
diff --git a/src/rtppollthread.cpp b/src/rtppollthread.cpp
new file mode 100644
index 0000000..cb7405d
--- /dev/null
+++ b/src/rtppollthread.cpp
@@ -0,0 +1,169 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtppollthread.h"
+
+#ifdef RTP_SUPPORT_THREAD
+
+#include "rtpsession.h"
+#include "rtcpscheduler.h"
+#include "rtperrors.h"
+#include "rtprawpacket.h"
+#include <time.h>
+
+#ifndef _WIN32_WCE
+ #include <iostream>
+#endif // _WIN32_WCE
+
+#include "rtpdebug.h"
+
+RTPPollThread::RTPPollThread(RTPSession &session,RTCPScheduler &sched):rtpsession(session),rtcpsched(sched)
+{
+ stop = false;
+ transmitter = 0;
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ timeinit.Dummy();
+#endif // WIN32 || _WIN32_WCE
+}
+
+RTPPollThread::~RTPPollThread()
+{
+ Stop();
+}
+
+int RTPPollThread::Start(RTPTransmitter *trans)
+{
+ if (JThread::IsRunning())
+ return ERR_RTP_POLLTHREAD_ALREADYRUNNING;
+
+ transmitter = trans;
+ if (!stopmutex.IsInitialized())
+ {
+ if (stopmutex.Init() < 0)
+ return ERR_RTP_POLLTHREAD_CANTINITMUTEX;
+ }
+ stop = false;
+ if (JThread::Start() < 0)
+ return ERR_RTP_POLLTHREAD_CANTSTARTTHREAD;
+ return 0;
+}
+
+void RTPPollThread::Stop()
+{
+ if (!IsRunning())
+ return;
+
+ stopmutex.Lock();
+ stop = true;
+ stopmutex.Unlock();
+
+ if (transmitter)
+ transmitter->AbortWait();
+
+ RTPTime thetime = RTPTime::CurrentTime();
+ bool done = false;
+
+ while (JThread::IsRunning() && !done)
+ {
+ // wait max 5 sec
+ RTPTime curtime = RTPTime::CurrentTime();
+ if ((curtime.GetDouble()-thetime.GetDouble()) > 5.0)
+ done = true;
+ RTPTime::Wait(RTPTime(0,10000));
+ }
+
+ if (JThread::IsRunning())
+ {
+#ifndef _WIN32_WCE
+ std::cerr << "RTPPollThread: Warning! Having to kill thread!" << std::endl;
+#endif // _WIN32_WCE
+ JThread::Kill();
+ }
+ stop = false;
+ transmitter = 0;
+}
+
+void *RTPPollThread::Thread()
+{
+ JThread::ThreadStarted();
+
+ bool stopthread;
+
+ stopmutex.Lock();
+ stopthread = stop;
+ stopmutex.Unlock();
+ while (!stopthread)
+ {
+ int status;
+
+ rtpsession.schedmutex.Lock();
+ rtpsession.sourcesmutex.Lock();
+
+ RTPTime rtcpdelay = rtcpsched.GetTransmissionDelay();
+
+ rtpsession.sourcesmutex.Unlock();
+ rtpsession.schedmutex.Unlock();
+
+ if ((status = transmitter->WaitForIncomingData(rtcpdelay)) < 0)
+ {
+ stopthread = true;
+ rtpsession.OnPollThreadError(status);
+ }
+ else
+ {
+ if ((status = transmitter->Poll()) < 0)
+ {
+ stopthread = true;
+ rtpsession.OnPollThreadError(status);
+ }
+ else
+ {
+ if ((status = rtpsession.ProcessPolledData()) < 0)
+ {
+ stopthread = true;
+ rtpsession.OnPollThreadError(status);
+ }
+ else
+ {
+ rtpsession.OnPollThreadStep();
+ stopmutex.Lock();
+ stopthread = stop;
+ stopmutex.Unlock();
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+#endif // RTP_SUPPORT_THREAD
+
diff --git a/src/rtppollthread.h b/src/rtppollthread.h
new file mode 100644
index 0000000..37350ec
--- /dev/null
+++ b/src/rtppollthread.h
@@ -0,0 +1,74 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtppollthread.h
+ */
+
+#ifndef RTPPOLLTHREAD_H
+
+#define RTPPOLLTHREAD_H
+
+#include "rtpconfig.h"
+
+#ifdef RTP_SUPPORT_THREAD
+
+#include "rtptransmitter.h"
+
+#include <jthread.h>
+#include <jmutex.h>
+#include <list>
+
+class RTPSession;
+class RTCPScheduler;
+
+class RTPPollThread : private JThread
+{
+public:
+ RTPPollThread(RTPSession &session,RTCPScheduler &rtcpsched);
+ ~RTPPollThread();
+ int Start(RTPTransmitter *trans);
+ void Stop();
+private:
+ void *Thread();
+
+ bool stop;
+ JMutex stopmutex;
+ RTPTransmitter *transmitter;
+
+ RTPSession &rtpsession;
+ RTCPScheduler &rtcpsched;
+};
+
+#endif // RTP_SUPPORT_THREAD
+
+#endif // RTPPOLLTHREAD_H
diff --git a/src/rtprandom.cpp b/src/rtprandom.cpp
new file mode 100644
index 0000000..310c65a
--- /dev/null
+++ b/src/rtprandom.cpp
@@ -0,0 +1,355 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#if defined(WIN32) && !defined(_WIN32_WCE)
+ #define _CRT_RAND_S
+#endif // WIN32 || _WIN32_WCE
+
+#include "rtprandom.h"
+#include <time.h>
+#ifndef WIN32
+ #include <unistd.h>
+#else
+ #ifndef _WIN32_WCE
+ #include <process.h>
+ #else
+ #include <windows.h>
+ #include <kfuncs.h>
+ #endif // _WIN32_WINCE
+ #include <stdlib.h>
+#endif // WIN32
+
+#include "rtpdebug.h"
+
+#if (defined(WIN32) && !defined(_WIN32_WCE)) && (defined(_MSC_VER) && _MSC_VER >= 1400 )
+ // If compiling on VC 8 or later for full Windows, we'll attempt to use rand_s,
+ // which generates better random numbers. However, its only supported on Windows XP,
+ // Windows Server 2003, and later, so we'll do a run-time check to see if we can
+ // use it (it won't work on Windows 2000 SP4 for example).
+ #define RTP_SUPPORT_RANDS
+ #define QUOTEPROCNAME(x) #x
+ #ifndef RtlGenRandom
+ #define RtlGenRandom SystemFunction036
+ #endif
+
+ static bool checked_rand_s = false;
+ static bool use_rand_s = false;
+#endif
+
+uint8_t GetRandom8_Default();
+uint16_t GetRandom16_Default();
+uint32_t GetRandom32_Default();
+double GetRandomDouble_Default();
+
+RTPRandom::RTPRandom()
+{
+
+#if defined(RTP_SUPPORT_GNUDRAND) || defined(RTP_SUPPORT_RANDR)
+ uint32_t x;
+
+ x = (uint32_t)getpid();
+ x += (uint32_t)time(0);
+ x -= (uint32_t)clock();
+ x ^= (uint32_t)((uint8_t *)this - (uint8_t *)0);
+
+#ifdef RTP_SUPPORT_GNUDRAND
+ srand48_r(x,&drandbuffer);
+#else
+ state = (unsigned int)x;
+#endif // RTP_SUPPORT_GNUDRAND
+
+#else // use simple rand and srand functions (or maybe rand_s)
+
+#ifdef RTP_SUPPORT_RANDS
+ if(checked_rand_s == false)
+ {
+ checked_rand_s = true;
+ use_rand_s = false;
+
+ HMODULE hAdvApi32 = LoadLibrary("ADVAPI32.DLL");
+ if(hAdvApi32 != NULL)
+ {
+ if(NULL != GetProcAddress( hAdvApi32, QUOTEPROCNAME( RtlGenRandom ) ))
+ {
+ use_rand_s = true;
+ }
+ FreeLibrary(hAdvApi32);
+ hAdvApi32 = NULL;
+ }
+ }
+
+ // Note: If we use the rand_s function, it does not require initialization of a seed.
+ if(!use_rand_s)
+ {
+#endif
+
+ uint32_t x;
+
+#ifndef _WIN32_WCE
+ x = (uint32_t)_getpid();
+ x += (uint32_t)time(0);
+ x -= (uint32_t)clock();
+#else
+ x = (uint32_t)GetCurrentProcessId();
+
+ FILETIME ft;
+ SYSTEMTIME st;
+
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st,&ft);
+
+ x += ft.dwLowDateTime;
+#endif // _WIN32_WCE
+ x ^= (uint32_t)((uint8_t *)this - (uint8_t *)0);
+ srand((unsigned int)x);
+
+#ifdef RTP_SUPPORT_RANDS
+ } // !support_rand_s
+#endif
+
+#endif // RTP_SUPPORT_GNUDRAND || RTP_SUPPORT_RANDR
+
+}
+
+RTPRandom::~RTPRandom()
+{
+}
+
+#if defined(RTP_SUPPORT_GNUDRAND)
+
+uint8_t RTPRandom::GetRandom8()
+{
+ double x;
+ drand48_r(&drandbuffer,&x);
+ uint8_t y = (uint8_t)(x*256.0);
+ return y;
+}
+
+uint16_t RTPRandom::GetRandom16()
+{
+ double x;
+ drand48_r(&drandbuffer,&x);
+ uint16_t y = (uint16_t)(x*65536.0);
+ return y;
+}
+
+uint32_t RTPRandom::GetRandom32()
+{
+ uint32_t a = GetRandom16();
+ uint32_t b = GetRandom16();
+ uint32_t y = (a << 16)|b;
+ return y;
+}
+
+double RTPRandom::GetRandomDouble()
+{
+ double x;
+ drand48_r(&drandbuffer,&x);
+ return x;
+}
+
+#elif defined(RTP_SUPPORT_RANDR)
+
+uint8_t RTPRandom::GetRandom8()
+{
+ uint8_t x;
+
+ x = (uint8_t)(256.0*((double)rand_r(&state))/((double)RAND_MAX+1.0));
+ return x;
+}
+
+uint16_t RTPRandom::GetRandom16()
+{
+ uint16_t x;
+
+ x = (uint16_t)(65536.0*((double)rand_r(&state))/((double)RAND_MAX+1.0));
+ return x;
+}
+
+uint32_t RTPRandom::GetRandom32()
+{
+ uint32_t x,y;
+
+ x = (uint32_t)(65536.0*((double)rand_r(&state))/((double)RAND_MAX+1.0));
+ y = x;
+ x = (uint32_t)(65536.0*((double)rand_r(&state))/((double)RAND_MAX+1.0));
+ y ^= (x<<8);
+ x = (uint32_t)(65536.0*((double)rand_r(&state))/((double)RAND_MAX+1.0));
+ y ^= (x<<16);
+
+ return y;
+}
+
+double RTPRandom::GetRandomDouble()
+{
+ double x = ((double)rand_r(&state))/((double)RAND_MAX+1.0);
+ return x;
+}
+
+#elif defined(RTP_SUPPORT_RANDS)
+
+uint8_t RTPRandom::GetRandom8()
+{
+ if(use_rand_s)
+ {
+ uint8_t x;
+ unsigned int r;
+
+ rand_s(&r);
+ x = (uint8_t)(256.0*((double)r)/((double)UINT_MAX+1.0));
+ return x;
+ }
+ else
+ {
+ return GetRandom8_Default();
+ }
+}
+
+uint16_t RTPRandom::GetRandom16()
+{
+ if(use_rand_s)
+ {
+ uint16_t x;
+ unsigned int r;
+
+ rand_s(&r);
+ x = (uint16_t)(65536.0*((double)r)/((double)UINT_MAX+1.0));
+ return x;
+ }
+ else
+ {
+ return GetRandom16_Default();
+ }
+}
+
+uint32_t RTPRandom::GetRandom32()
+{
+ if(use_rand_s)
+ {
+ uint32_t x,y;
+ unsigned int r;
+
+ rand_s(&r);
+ x = (uint32_t)(65536.0*((double)r)/((double)UINT_MAX+1.0));
+ y = x;
+ rand_s(&r);
+ x = (uint32_t)(65536.0*((double)r)/((double)UINT_MAX+1.0));
+ y ^= (x<<8);
+ rand_s(&r);
+ x = (uint32_t)(65536.0*((double)r)/((double)UINT_MAX+1.0));
+ y ^= (x<<16);
+
+ return y;
+ }
+ else
+ {
+ return GetRandom32_Default();
+ }
+}
+
+double RTPRandom::GetRandomDouble()
+{
+ if(use_rand_s)
+ {
+ unsigned int r;
+
+ rand_s(&r);
+ double x = ((double)r)/((double)UINT_MAX+1.0);
+ return x;
+ }
+ else
+ {
+ return GetRandomDouble_Default();
+ }
+}
+
+#else // use rand()
+
+uint8_t RTPRandom::GetRandom8()
+{
+ return GetRandom8_Default();
+}
+
+uint16_t RTPRandom::GetRandom16()
+{
+ return GetRandom16_Default();
+}
+
+uint32_t RTPRandom::GetRandom32()
+{
+ return GetRandom32_Default();
+}
+
+double RTPRandom::GetRandomDouble()
+{
+ return GetRandomDouble_Default();
+}
+
+#endif // RTP_SUPPORT_GNUDRAND
+
+
+uint8_t GetRandom8_Default()
+{
+ uint8_t x;
+
+ x = (uint8_t)(256.0*((double)rand())/((double)RAND_MAX+1.0));
+ return x;
+}
+
+uint16_t GetRandom16_Default()
+{
+ uint16_t x;
+
+ x = (uint16_t)(65536.0*((double)rand())/((double)RAND_MAX+1.0));
+ return x;
+}
+
+uint32_t GetRandom32_Default()
+{
+ uint32_t x,y;
+
+ x = (uint32_t)(65536.0*((double)rand())/((double)RAND_MAX+1.0));
+ y = x;
+ x = (uint32_t)(65536.0*((double)rand())/((double)RAND_MAX+1.0));
+ y ^= (x<<8);
+ x = (uint32_t)(65536.0*((double)rand())/((double)RAND_MAX+1.0));
+ y ^= (x<<16);
+
+ return y;
+}
+
+double GetRandomDouble_Default()
+{
+ double x = ((double)rand())/((double)RAND_MAX+1.0);
+ return x;
+}
+
diff --git a/src/rtprandom.h b/src/rtprandom.h
new file mode 100644
index 0000000..8a487b1
--- /dev/null
+++ b/src/rtprandom.h
@@ -0,0 +1,72 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtprandom.h
+ */
+
+#ifndef RTPRANDOM_H
+
+#define RTPRANDOM_H
+
+#include "rtpconfig.h"
+#include "rtptypes.h"
+#include <stdlib.h>
+
+/** The RTPRandom class can be used to generate random numbers. */
+class RTPRandom
+{
+public:
+ RTPRandom();
+ ~RTPRandom();
+
+ /** Returns a random eight bit value. */
+ uint8_t GetRandom8();
+
+ /** Returns a random sixteen bit value. */
+ uint16_t GetRandom16();
+
+ /** Returns a random thirty-two bit value. */
+ uint32_t GetRandom32();
+
+ /** Returns a random number between $0.0$ and $1.0$. */
+ double GetRandomDouble();
+private:
+#if defined(RTP_SUPPORT_GNUDRAND)
+ struct drand48_data drandbuffer;
+#elif defined(RTP_SUPPORT_RANDR)
+ unsigned int state;
+#endif // RTP_SUPPORT_GNUDRAND
+};
+
+#endif // RTPRANDOM_H
+
diff --git a/src/rtprawpacket.h b/src/rtprawpacket.h
new file mode 100644
index 0000000..1b4029a
--- /dev/null
+++ b/src/rtprawpacket.h
@@ -0,0 +1,109 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtprawpacket.h
+ */
+
+#ifndef RTPRAWPACKET_H
+
+#define RTPRAWPACKET_H
+
+#include "rtpconfig.h"
+#include "rtptimeutilities.h"
+#include "rtpaddress.h"
+#include "rtptypes.h"
+#include "rtpmemoryobject.h"
+
+/** This class is used by the transmission component to store the incoming RTP and RTCP data in. */
+class RTPRawPacket : public RTPMemoryObject
+{
+public:
+ /** Creates an instance which stores data from \c data with length \c datalen.
+ * Creates an instance which stores data from \c data with length \c datalen. Only the pointer
+ * to the data is stored, no actual copy is made! The address from which this packet originated
+ * is set to \c address and the time at which the packet was received is set to \c recvtime.
+ * The flag which indicates whether this data is RTP or RTCP data is set to \c rtp. A memory
+ * manager can be installed as well.
+ */
+ RTPRawPacket(uint8_t *data,size_t datalen,RTPAddress *address,RTPTime &recvtime,bool rtp,RTPMemoryManager *mgr = 0);
+ ~RTPRawPacket();
+
+ /** Returns the pointer to the data which is contained in this packet. */
+ uint8_t *GetData() { return packetdata; }
+
+ /** Returns the length of the packet described by this instance. */
+ size_t GetDataLength() const { return packetdatalength; }
+
+ /** Returns the time at which this packet was received. */
+ RTPTime GetReceiveTime() const { return receivetime; }
+
+ /** Returns the address stored in this packet. */
+ const RTPAddress *GetSenderAddress() const { return senderaddress; }
+
+ /** Returns \c true if this data is RTP data, \c false if it is RTCP data. */
+ bool IsRTP() const { return isrtp; }
+
+ /** Sets the pointer to the data stored in this packet to zero.
+ * Sets the pointer to the data stored in this packet to zero. This will prevent
+ * a \c delete call for the actual data when the destructor of RTPRawPacket is called.
+ * This function is used by the RTPPacket and RTCPCompoundPacket classes to obtain
+ * the packet data (without having to copy it) and to make sure the data isn't deleted
+ * when the destructor of RTPRawPacket is called.
+ */
+ void ZeroData() { packetdata = 0; packetdatalength = 0; }
+private:
+ uint8_t *packetdata;
+ size_t packetdatalength;
+ RTPTime receivetime;
+ RTPAddress *senderaddress;
+ bool isrtp;
+};
+
+inline RTPRawPacket::RTPRawPacket(uint8_t *data,size_t datalen,RTPAddress *address,RTPTime &recvtime,bool rtp,RTPMemoryManager *mgr):RTPMemoryObject(mgr),receivetime(recvtime)
+{
+ packetdata = data;
+ packetdatalength = datalen;
+ senderaddress = address;
+ isrtp = rtp;
+}
+
+inline RTPRawPacket::~RTPRawPacket()
+{
+ if (packetdata)
+ RTPDeleteByteArray(packetdata,GetMemoryManager());
+ if (senderaddress)
+ RTPDelete(senderaddress,GetMemoryManager());
+}
+
+#endif // RTPRAWPACKET_H
+
diff --git a/src/rtpsession.cpp b/src/rtpsession.cpp
new file mode 100644
index 0000000..cce6195
--- /dev/null
+++ b/src/rtpsession.cpp
@@ -0,0 +1,1477 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtpsession.h"
+#include "rtperrors.h"
+#include "rtppollthread.h"
+#include "rtpudpv4transmitter.h"
+#include "rtpudpv6transmitter.h"
+#include "rtpsessionparams.h"
+#include "rtpdefines.h"
+#include "rtprawpacket.h"
+#include "rtppacket.h"
+#include "rtptimeutilities.h"
+#include "rtpmemorymanager.h"
+#ifdef RTP_SUPPORT_SENDAPP
+ #include "rtcpcompoundpacket.h"
+#endif // RTP_SUPPORT_SENDAPP
+#ifndef WIN32
+ #include <unistd.h>
+ #include <stdlib.h>
+#else
+ #include <winbase.h>
+#endif // WIN32
+
+#ifdef RTPDEBUG
+ #include <iostream>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+#ifdef RTP_SUPPORT_THREAD
+ #define SOURCES_LOCK { if (usingpollthread) sourcesmutex.Lock(); }
+ #define SOURCES_UNLOCK { if (usingpollthread) sourcesmutex.Unlock(); }
+ #define BUILDER_LOCK { if (usingpollthread) buildermutex.Lock(); }
+ #define BUILDER_UNLOCK { if (usingpollthread) buildermutex.Unlock(); }
+ #define SCHED_LOCK { if (usingpollthread) schedmutex.Lock(); }
+ #define SCHED_UNLOCK { if (usingpollthread) schedmutex.Unlock(); }
+ #define PACKSENT_LOCK { if (usingpollthread) packsentmutex.Lock(); }
+ #define PACKSENT_UNLOCK { if (usingpollthread) packsentmutex.Unlock(); }
+#else
+ #define SOURCES_LOCK
+ #define SOURCES_UNLOCK
+ #define BUILDER_LOCK
+ #define BUILDER_UNLOCK
+ #define SCHED_LOCK
+ #define SCHED_UNLOCK
+ #define PACKSENT_LOCK
+ #define PACKSENT_UNLOCK
+#endif // RTP_SUPPORT_THREAD
+
+RTPSession::RTPSession(RTPMemoryManager *mgr)
+ : RTPMemoryObject(mgr),sources(*this,mgr),packetbuilder(mgr),rtcpsched(sources),rtcpbuilder(sources,packetbuilder,mgr),
+ collisionlist(mgr)
+{
+ created = false;
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ timeinit.Dummy();
+#endif // WIN32 || _WIN32_WCE
+}
+
+RTPSession::~RTPSession()
+{
+ Destroy();
+}
+
+int RTPSession::Create(const RTPSessionParams &sessparams,const RTPTransmissionParams *transparams /* = 0 */,
+ RTPTransmitter::TransmissionProtocol protocol)
+{
+ int status;
+
+ if (created)
+ return ERR_RTP_SESSION_ALREADYCREATED;
+
+ usingpollthread = sessparams.IsUsingPollThread();
+ useSR_BYEifpossible = sessparams.GetSenderReportForBYE();
+ sentpackets = false;
+
+ // Check max packet size
+
+ if ((maxpacksize = sessparams.GetMaximumPacketSize()) < RTP_MINPACKETSIZE)
+ return ERR_RTP_SESSION_MAXPACKETSIZETOOSMALL;
+
+ // Initialize the transmission component
+
+ rtptrans = 0;
+ switch(protocol)
+ {
+ case RTPTransmitter::IPv4UDPProto:
+ rtptrans = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPTRANSMITTER) RTPUDPv4Transmitter(GetMemoryManager());
+ break;
+#ifdef RTP_SUPPORT_IPV6
+ case RTPTransmitter::IPv6UDPProto:
+ rtptrans = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPTRANSMITTER) RTPUDPv6Transmitter(GetMemoryManager());
+ break;
+#endif // RTP_SUPPORT_IPV6
+ case RTPTransmitter::UserDefinedProto:
+ rtptrans = NewUserDefinedTransmitter();
+ if (rtptrans == 0)
+ return ERR_RTP_SESSION_USERDEFINEDTRANSMITTERNULL;
+ break;
+ default:
+ return ERR_RTP_SESSION_UNSUPPORTEDTRANSMISSIONPROTOCOL;
+ }
+
+ if (rtptrans == 0)
+ return ERR_RTP_OUTOFMEM;
+ if ((status = rtptrans->Init(usingpollthread)) < 0)
+ {
+ RTPDelete(rtptrans,GetMemoryManager());
+ return status;
+ }
+ if ((status = rtptrans->Create(maxpacksize,transparams)) < 0)
+ {
+ RTPDelete(rtptrans,GetMemoryManager());
+ return status;
+ }
+
+ deletetransmitter = true;
+ return InternalCreate(sessparams);
+}
+
+int RTPSession::Create(const RTPSessionParams &sessparams,RTPTransmitter *transmitter)
+{
+ int status;
+
+ if (created)
+ return ERR_RTP_SESSION_ALREADYCREATED;
+
+ usingpollthread = sessparams.IsUsingPollThread();
+ useSR_BYEifpossible = sessparams.GetSenderReportForBYE();
+ sentpackets = false;
+
+ // Check max packet size
+
+ if ((maxpacksize = sessparams.GetMaximumPacketSize()) < RTP_MINPACKETSIZE)
+ return ERR_RTP_SESSION_MAXPACKETSIZETOOSMALL;
+
+ rtptrans = transmitter;
+
+ if ((status = rtptrans->SetMaximumPacketSize(maxpacksize)) < 0)
+ return status;
+
+ deletetransmitter = false;
+ return InternalCreate(sessparams);
+}
+
+int RTPSession::InternalCreate(const RTPSessionParams &sessparams)
+{
+ int status;
+
+ // Initialize packet builder
+
+ if ((status = packetbuilder.Init(maxpacksize)) < 0)
+ {
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ return status;
+ }
+
+#ifdef RTP_SUPPORT_PROBATION
+
+ // Set probation type
+ sources.SetProbationType(sessparams.GetProbationType());
+
+#endif // RTP_SUPPORT_PROBATION
+
+ // Add our own ssrc to the source table
+
+ if ((status = sources.CreateOwnSSRC(packetbuilder.GetSSRC())) < 0)
+ {
+ packetbuilder.Destroy();
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ return status;
+ }
+
+ // Set the initial receive mode
+
+ if ((status = rtptrans->SetReceiveMode(sessparams.GetReceiveMode())) < 0)
+ {
+ packetbuilder.Destroy();
+ sources.Clear();
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ return status;
+ }
+
+ // Init the RTCP packet builder
+
+ double timestampunit = sessparams.GetOwnTimestampUnit();
+ uint8_t buf[1024];
+ size_t buflen = 1024;
+
+ if ((status = CreateCNAME(buf,&buflen,sessparams.GetResolveLocalHostname())) < 0)
+ {
+ packetbuilder.Destroy();
+ sources.Clear();
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ return status;
+ }
+
+ if ((status = rtcpbuilder.Init(maxpacksize,timestampunit,buf,buflen)) < 0)
+ {
+ packetbuilder.Destroy();
+ sources.Clear();
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ return status;
+ }
+
+ // Set scheduler parameters
+
+ rtcpsched.Reset();
+ rtcpsched.SetHeaderOverhead(rtptrans->GetHeaderOverhead());
+
+ RTCPSchedulerParams schedparams;
+
+ sessionbandwidth = sessparams.GetSessionBandwidth();
+ controlfragment = sessparams.GetControlTrafficFraction();
+
+ if ((status = schedparams.SetRTCPBandwidth(sessionbandwidth*controlfragment)) < 0)
+ {
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ packetbuilder.Destroy();
+ sources.Clear();
+ rtcpbuilder.Destroy();
+ return status;
+ }
+ if ((status = schedparams.SetSenderBandwidthFraction(sessparams.GetSenderControlBandwidthFraction())) < 0)
+ {
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ packetbuilder.Destroy();
+ sources.Clear();
+ rtcpbuilder.Destroy();
+ return status;
+ }
+ if ((status = schedparams.SetMinimumTransmissionInterval(sessparams.GetMinimumRTCPTransmissionInterval())) < 0)
+ {
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ packetbuilder.Destroy();
+ sources.Clear();
+ rtcpbuilder.Destroy();
+ return status;
+ }
+ schedparams.SetUseHalfAtStartup(sessparams.GetUseHalfRTCPIntervalAtStartup());
+ schedparams.SetRequestImmediateBYE(sessparams.GetRequestImmediateBYE());
+
+ rtcpsched.SetParameters(schedparams);
+
+ // copy other parameters
+
+ acceptownpackets = sessparams.AcceptOwnPackets();
+ membermultiplier = sessparams.GetSourceTimeoutMultiplier();
+ sendermultiplier = sessparams.GetSenderTimeoutMultiplier();
+ byemultiplier = sessparams.GetBYETimeoutMultiplier();
+ collisionmultiplier = sessparams.GetCollisionTimeoutMultiplier();
+ notemultiplier = sessparams.GetNoteTimeoutMultiplier();
+
+ // Do thread stuff if necessary
+
+#ifdef RTP_SUPPORT_THREAD
+ pollthread = 0;
+ if (usingpollthread)
+ {
+ if (!sourcesmutex.IsInitialized())
+ {
+ if (sourcesmutex.Init() < 0)
+ {
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ packetbuilder.Destroy();
+ sources.Clear();
+ rtcpbuilder.Destroy();
+ return ERR_RTP_SESSION_CANTINITMUTEX;
+ }
+ }
+ if (!buildermutex.IsInitialized())
+ {
+ if (buildermutex.Init() < 0)
+ {
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ packetbuilder.Destroy();
+ sources.Clear();
+ rtcpbuilder.Destroy();
+ return ERR_RTP_SESSION_CANTINITMUTEX;
+ }
+ }
+ if (!schedmutex.IsInitialized())
+ {
+ if (schedmutex.Init() < 0)
+ {
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ packetbuilder.Destroy();
+ sources.Clear();
+ rtcpbuilder.Destroy();
+ return ERR_RTP_SESSION_CANTINITMUTEX;
+ }
+ }
+ if (!packsentmutex.IsInitialized())
+ {
+ if (packsentmutex.Init() < 0)
+ {
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ packetbuilder.Destroy();
+ sources.Clear();
+ rtcpbuilder.Destroy();
+ return ERR_RTP_SESSION_CANTINITMUTEX;
+ }
+ }
+
+ pollthread = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPPOLLTHREAD) RTPPollThread(*this,rtcpsched);
+ if (pollthread == 0)
+ {
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ packetbuilder.Destroy();
+ sources.Clear();
+ rtcpbuilder.Destroy();
+ return ERR_RTP_OUTOFMEM;
+ }
+ if ((status = pollthread->Start(rtptrans)) < 0)
+ {
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ RTPDelete(pollthread,GetMemoryManager());
+ packetbuilder.Destroy();
+ sources.Clear();
+ rtcpbuilder.Destroy();
+ return status;
+ }
+ }
+#endif // RTP_SUPPORT_THREAD
+
+ created = true;
+ return 0;
+}
+
+
+void RTPSession::Destroy()
+{
+ if (!created)
+ return;
+
+#ifdef RTP_SUPPORT_THREAD
+ if (pollthread)
+ RTPDelete(pollthread,GetMemoryManager());
+#endif // RTP_SUPPORT_THREAD
+
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ packetbuilder.Destroy();
+ rtcpbuilder.Destroy();
+ rtcpsched.Reset();
+ collisionlist.Clear();
+ sources.Clear();
+
+ std::list<RTCPCompoundPacket *>::const_iterator it;
+
+ for (it = byepackets.begin() ; it != byepackets.end() ; it++)
+ RTPDelete(*it,GetMemoryManager());
+ byepackets.clear();
+
+ created = false;
+}
+
+void RTPSession::BYEDestroy(const RTPTime &maxwaittime,const void *reason,size_t reasonlength)
+{
+ if (!created)
+ return;
+
+ // first, stop the thread so we have full control over all components
+
+#ifdef RTP_SUPPORT_THREAD
+ if (pollthread)
+ RTPDelete(pollthread,GetMemoryManager());
+#endif // RTP_SUPPORT_THREAD
+
+ RTPTime stoptime = RTPTime::CurrentTime();
+ stoptime += maxwaittime;
+
+ // add bye packet to the list if we've sent data
+
+ RTCPCompoundPacket *pack;
+
+ if (sentpackets)
+ {
+ int status;
+
+ reasonlength = (reasonlength>RTCP_BYE_MAXREASONLENGTH)?RTCP_BYE_MAXREASONLENGTH:reasonlength;
+ status = rtcpbuilder.BuildBYEPacket(&pack,reason,reasonlength,useSR_BYEifpossible);
+ if (status >= 0)
+ {
+ byepackets.push_back(pack);
+
+ if (byepackets.size() == 1)
+ rtcpsched.ScheduleBYEPacket(pack->GetCompoundPacketLength());
+ }
+ }
+
+ if (!byepackets.empty())
+ {
+ bool done = false;
+
+ while (!done)
+ {
+ RTPTime curtime = RTPTime::CurrentTime();
+
+ if (curtime >= stoptime)
+ done = true;
+
+ if (rtcpsched.IsTime())
+ {
+ pack = *(byepackets.begin());
+ byepackets.pop_front();
+
+ rtptrans->SendRTCPData(pack->GetCompoundPacketData(),pack->GetCompoundPacketLength());
+
+ OnSendRTCPCompoundPacket(pack); // we'll place this after the actual send to avoid tampering
+
+ RTPDelete(pack,GetMemoryManager());
+ if (!byepackets.empty()) // more bye packets to send, schedule them
+ rtcpsched.ScheduleBYEPacket((*(byepackets.begin()))->GetCompoundPacketLength());
+ else
+ done = true;
+ }
+ if (!done)
+ RTPTime::Wait(RTPTime(0,100000));
+ }
+ }
+
+ if (deletetransmitter)
+ RTPDelete(rtptrans,GetMemoryManager());
+ packetbuilder.Destroy();
+ rtcpbuilder.Destroy();
+ rtcpsched.Reset();
+ collisionlist.Clear();
+ sources.Clear();
+
+ // clear rest of bye packets
+ std::list<RTCPCompoundPacket *>::const_iterator it;
+
+ for (it = byepackets.begin() ; it != byepackets.end() ; it++)
+ RTPDelete(*it,GetMemoryManager());
+ byepackets.clear();
+
+ created = false;
+}
+
+bool RTPSession::IsActive()
+{
+ return created;
+}
+
+uint32_t RTPSession::GetLocalSSRC()
+{
+ if (!created)
+ return 0;
+
+ uint32_t ssrc;
+
+ BUILDER_LOCK
+ ssrc = packetbuilder.GetSSRC();
+ BUILDER_UNLOCK
+ return ssrc;
+}
+
+int RTPSession::AddDestination(const RTPAddress &addr)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+ return rtptrans->AddDestination(addr);
+}
+
+int RTPSession::DeleteDestination(const RTPAddress &addr)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+ return rtptrans->DeleteDestination(addr);
+}
+
+void RTPSession::ClearDestinations()
+{
+ if (!created)
+ return;
+ rtptrans->ClearDestinations();
+}
+
+bool RTPSession::SupportsMulticasting()
+{
+ if (!created)
+ return false;
+ return rtptrans->SupportsMulticasting();
+}
+
+int RTPSession::JoinMulticastGroup(const RTPAddress &addr)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+ return rtptrans->JoinMulticastGroup(addr);
+}
+
+int RTPSession::LeaveMulticastGroup(const RTPAddress &addr)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+ return rtptrans->LeaveMulticastGroup(addr);
+}
+
+void RTPSession::LeaveAllMulticastGroups()
+{
+ if (!created)
+ return;
+ rtptrans->LeaveAllMulticastGroups();
+}
+
+int RTPSession::SendPacket(const void *data,size_t len)
+{
+ int status;
+
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ BUILDER_LOCK
+ if ((status = packetbuilder.BuildPacket(data,len)) < 0)
+ {
+ BUILDER_UNLOCK
+ return status;
+ }
+ if ((status = rtptrans->SendRTPData(packetbuilder.GetPacket(),packetbuilder.GetPacketLength())) < 0)
+ {
+ BUILDER_UNLOCK
+ return status;
+ }
+ BUILDER_UNLOCK
+
+ SOURCES_LOCK
+ sources.SentRTPPacket();
+ SOURCES_UNLOCK
+ PACKSENT_LOCK
+ sentpackets = true;
+ PACKSENT_UNLOCK
+ return 0;
+}
+
+int RTPSession::SendPacket(const void *data,size_t len,
+ uint8_t pt,bool mark,uint32_t timestampinc)
+{
+ int status;
+
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ BUILDER_LOCK
+ if ((status = packetbuilder.BuildPacket(data,len,pt,mark,timestampinc)) < 0)
+ {
+ BUILDER_UNLOCK
+ return status;
+ }
+ if ((status = rtptrans->SendRTPData(packetbuilder.GetPacket(),packetbuilder.GetPacketLength())) < 0)
+ {
+ BUILDER_UNLOCK
+ return status;
+ }
+ BUILDER_UNLOCK
+
+ SOURCES_LOCK
+ sources.SentRTPPacket();
+ SOURCES_UNLOCK
+ PACKSENT_LOCK
+ sentpackets = true;
+ PACKSENT_UNLOCK
+ return 0;
+}
+
+int RTPSession::SendPacketEx(const void *data,size_t len,
+ uint16_t hdrextID,const void *hdrextdata,size_t numhdrextwords)
+{
+ int status;
+
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ BUILDER_LOCK
+ if ((status = packetbuilder.BuildPacketEx(data,len,hdrextID,hdrextdata,numhdrextwords)) < 0)
+ {
+ BUILDER_UNLOCK
+ return status;
+ }
+ if ((status = rtptrans->SendRTPData(packetbuilder.GetPacket(),packetbuilder.GetPacketLength())) < 0)
+ {
+ BUILDER_UNLOCK
+ return status;
+ }
+ BUILDER_UNLOCK
+
+ SOURCES_LOCK
+ sources.SentRTPPacket();
+ SOURCES_UNLOCK
+ PACKSENT_LOCK
+ sentpackets = true;
+ PACKSENT_UNLOCK
+ return 0;
+}
+
+int RTPSession::SendPacketEx(const void *data,size_t len,
+ uint8_t pt,bool mark,uint32_t timestampinc,
+ uint16_t hdrextID,const void *hdrextdata,size_t numhdrextwords)
+{
+ int status;
+
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ BUILDER_LOCK
+ if ((status = packetbuilder.BuildPacketEx(data,len,pt,mark,timestampinc,hdrextID,hdrextdata,numhdrextwords)) < 0)
+ {
+ BUILDER_UNLOCK
+ return status;
+ }
+ if ((status = rtptrans->SendRTPData(packetbuilder.GetPacket(),packetbuilder.GetPacketLength())) < 0)
+ {
+ BUILDER_UNLOCK
+ return status;
+ }
+ BUILDER_UNLOCK
+
+ SOURCES_LOCK
+ sources.SentRTPPacket();
+ SOURCES_UNLOCK
+ PACKSENT_LOCK
+ sentpackets = true;
+ PACKSENT_UNLOCK
+ return 0;
+}
+
+#ifdef RTP_SUPPORT_SENDAPP
+
+int RTPSession::SendRTCPAPPPacket(uint8_t subtype, const uint8_t name[4], const void *appdata, size_t appdatalen)
+{
+ int status;
+
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ BUILDER_LOCK
+ uint32_t ssrc = packetbuilder.GetSSRC();
+ BUILDER_UNLOCK
+
+ RTCPCompoundPacketBuilder pb(GetMemoryManager());
+
+ status = pb.InitBuild(maxpacksize);
+
+ if(status < 0)
+ return status;
+
+ //first packet in an rtcp compound packet should always be SR or RR
+ if((status = pb.StartReceiverReport(ssrc)) < 0)
+ return status;
+
+ //add SDES packet with CNAME item
+ if ((status = pb.AddSDESSource(ssrc)) < 0)
+ return status;
+
+ BUILDER_LOCK
+ size_t owncnamelen = 0;
+ uint8_t *owncname = rtcpbuilder.GetLocalCNAME(&owncnamelen);
+
+ if ((status = pb.AddSDESNormalItem(RTCPSDESPacket::CNAME,owncname,owncnamelen)) < 0)
+ {
+ BUILDER_UNLOCK
+ return status;
+ }
+ BUILDER_UNLOCK
+
+ //add our application specific packet
+ if((status = pb.AddAPPPacket(subtype, ssrc, name, appdata, appdatalen)) < 0)
+ return status;
+
+ if((status = pb.EndBuild()) < 0)
+ return status;
+
+ //send packet
+ status = rtptrans->SendRTCPData(pb.GetCompoundPacketData(),pb.GetCompoundPacketLength());
+ if(status < 0)
+ return status;
+
+ PACKSENT_LOCK
+ sentpackets = true;
+ PACKSENT_UNLOCK
+
+ return pb.GetCompoundPacketLength();
+}
+
+#endif // RTP_SUPPORT_SENDAPP
+
+int RTPSession::SetDefaultPayloadType(uint8_t pt)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ int status;
+
+ BUILDER_LOCK
+ status = packetbuilder.SetDefaultPayloadType(pt);
+ BUILDER_UNLOCK
+ return status;
+}
+
+int RTPSession::SetDefaultMark(bool m)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ int status;
+
+ BUILDER_LOCK
+ status = packetbuilder.SetDefaultMark(m);
+ BUILDER_UNLOCK
+ return status;
+}
+
+int RTPSession::SetDefaultTimestampIncrement(uint32_t timestampinc)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ int status;
+
+ BUILDER_LOCK
+ status = packetbuilder.SetDefaultTimestampIncrement(timestampinc);
+ BUILDER_UNLOCK
+ return status;
+}
+
+int RTPSession::IncrementTimestamp(uint32_t inc)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ int status;
+
+ BUILDER_LOCK
+ status = packetbuilder.IncrementTimestamp(inc);
+ BUILDER_UNLOCK
+ return status;
+}
+
+int RTPSession::IncrementTimestampDefault()
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ int status;
+
+ BUILDER_LOCK
+ status = packetbuilder.IncrementTimestampDefault();
+ BUILDER_UNLOCK
+ return status;
+}
+
+int RTPSession::SetPreTransmissionDelay(const RTPTime &delay)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ int status;
+
+ BUILDER_LOCK
+ status = rtcpbuilder.SetPreTransmissionDelay(delay);
+ BUILDER_UNLOCK
+ return status;
+}
+
+RTPTransmissionInfo *RTPSession::GetTransmissionInfo()
+{
+ if (!created)
+ return 0;
+ return rtptrans->GetTransmissionInfo();
+}
+
+void RTPSession::DeleteTransmissionInfo(RTPTransmissionInfo *inf)
+{
+ RTPDelete(inf,GetMemoryManager());
+}
+
+int RTPSession::Poll()
+{
+ int status;
+
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+ if (usingpollthread)
+ return ERR_RTP_SESSION_USINGPOLLTHREAD;
+ if ((status = rtptrans->Poll()) < 0)
+ return status;
+ return ProcessPolledData();
+}
+
+int RTPSession::WaitForIncomingData(const RTPTime &delay,bool *dataavailable)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+ if (usingpollthread)
+ return ERR_RTP_SESSION_USINGPOLLTHREAD;
+ return rtptrans->WaitForIncomingData(delay,dataavailable);
+}
+
+int RTPSession::AbortWait()
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+ if (usingpollthread)
+ return ERR_RTP_SESSION_USINGPOLLTHREAD;
+ return rtptrans->AbortWait();
+}
+
+RTPTime RTPSession::GetRTCPDelay()
+{
+ if (!created)
+ return RTPTime(0,0);
+ if (usingpollthread)
+ return RTPTime(0,0);
+
+ SOURCES_LOCK
+ SCHED_LOCK
+ RTPTime t = rtcpsched.GetTransmissionDelay();
+ SCHED_UNLOCK
+ SOURCES_UNLOCK
+ return t;
+}
+
+int RTPSession::BeginDataAccess()
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+ SOURCES_LOCK
+ return 0;
+}
+
+bool RTPSession::GotoFirstSource()
+{
+ if (!created)
+ return false;
+ return sources.GotoFirstSource();
+}
+
+bool RTPSession::GotoNextSource()
+{
+ if (!created)
+ return false;
+ return sources.GotoNextSource();
+}
+
+bool RTPSession::GotoPreviousSource()
+{
+ if (!created)
+ return false;
+ return sources.GotoPreviousSource();
+}
+
+bool RTPSession::GotoFirstSourceWithData()
+{
+ if (!created)
+ return false;
+ return sources.GotoFirstSourceWithData();
+}
+
+bool RTPSession::GotoNextSourceWithData()
+{
+ if (!created)
+ return false;
+ return sources.GotoNextSourceWithData();
+}
+
+bool RTPSession::GotoPreviousSourceWithData()
+{
+ if (!created)
+ return false;
+ return sources.GotoPreviousSourceWithData();
+}
+
+RTPSourceData *RTPSession::GetCurrentSourceInfo()
+{
+ if (!created)
+ return 0;
+ return sources.GetCurrentSourceInfo();
+}
+
+RTPSourceData *RTPSession::GetSourceInfo(uint32_t ssrc)
+{
+ if (!created)
+ return 0;
+ return sources.GetSourceInfo(ssrc);
+}
+
+RTPPacket *RTPSession::GetNextPacket()
+{
+ if (!created)
+ return 0;
+ return sources.GetNextPacket();
+}
+
+void RTPSession::DeletePacket(RTPPacket *p)
+{
+ RTPDelete(p,GetMemoryManager());
+}
+
+int RTPSession::EndDataAccess()
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+ SOURCES_UNLOCK
+ return 0;
+}
+
+int RTPSession::SetReceiveMode(RTPTransmitter::ReceiveMode m)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+ return rtptrans->SetReceiveMode(m);
+}
+
+int RTPSession::AddToIgnoreList(const RTPAddress &addr)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+ return rtptrans->AddToIgnoreList(addr);
+}
+
+int RTPSession::DeleteFromIgnoreList(const RTPAddress &addr)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+ return rtptrans->DeleteFromIgnoreList(addr);
+}
+
+void RTPSession::ClearIgnoreList()
+{
+ if (!created)
+ return;
+ rtptrans->ClearIgnoreList();
+}
+
+int RTPSession::AddToAcceptList(const RTPAddress &addr)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+ return rtptrans->AddToAcceptList(addr);
+}
+
+int RTPSession::DeleteFromAcceptList(const RTPAddress &addr)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+ return rtptrans->DeleteFromAcceptList(addr);
+}
+
+void RTPSession::ClearAcceptList()
+{
+ if (!created)
+ return;
+ rtptrans->ClearAcceptList();
+}
+
+int RTPSession::SetMaximumPacketSize(size_t s)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ if (s < RTP_MINPACKETSIZE)
+ return ERR_RTP_SESSION_MAXPACKETSIZETOOSMALL;
+
+ int status;
+
+ if ((status = rtptrans->SetMaximumPacketSize(s)) < 0)
+ return status;
+
+ BUILDER_LOCK
+ if ((status = packetbuilder.SetMaximumPacketSize(s)) < 0)
+ {
+ BUILDER_UNLOCK
+ // restore previous max packet size
+ rtptrans->SetMaximumPacketSize(maxpacksize);
+ return status;
+ }
+ if ((status = rtcpbuilder.SetMaximumPacketSize(s)) < 0)
+ {
+ // restore previous max packet size
+ packetbuilder.SetMaximumPacketSize(maxpacksize);
+ BUILDER_UNLOCK
+ rtptrans->SetMaximumPacketSize(maxpacksize);
+ return status;
+ }
+ BUILDER_UNLOCK
+ maxpacksize = s;
+ return 0;
+}
+
+int RTPSession::SetSessionBandwidth(double bw)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ int status;
+ SCHED_LOCK
+ RTCPSchedulerParams p = rtcpsched.GetParameters();
+ status = p.SetRTCPBandwidth(bw*controlfragment);
+ if (status >= 0)
+ {
+ rtcpsched.SetParameters(p);
+ sessionbandwidth = bw;
+ }
+ SCHED_UNLOCK
+ return status;
+}
+
+int RTPSession::SetTimestampUnit(double u)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ int status;
+
+ BUILDER_LOCK
+ status = rtcpbuilder.SetTimestampUnit(u);
+ BUILDER_UNLOCK
+ return status;
+}
+
+void RTPSession::SetNameInterval(int count)
+{
+ if (!created)
+ return;
+ BUILDER_LOCK
+ rtcpbuilder.SetNameInterval(count);
+ BUILDER_UNLOCK
+}
+
+void RTPSession::SetEMailInterval(int count)
+{
+ if (!created)
+ return;
+ BUILDER_LOCK
+ rtcpbuilder.SetEMailInterval(count);
+ BUILDER_UNLOCK
+}
+
+void RTPSession::SetLocationInterval(int count)
+{
+ if (!created)
+ return;
+ BUILDER_LOCK
+ rtcpbuilder.SetLocationInterval(count);
+ BUILDER_UNLOCK
+}
+
+void RTPSession::SetPhoneInterval(int count)
+{
+ if (!created)
+ return;
+ BUILDER_LOCK
+ rtcpbuilder.SetPhoneInterval(count);
+ BUILDER_UNLOCK
+}
+
+void RTPSession::SetToolInterval(int count)
+{
+ if (!created)
+ return;
+ BUILDER_LOCK
+ rtcpbuilder.SetToolInterval(count);
+ BUILDER_UNLOCK
+}
+
+void RTPSession::SetNoteInterval(int count)
+{
+ if (!created)
+ return;
+ BUILDER_LOCK
+ rtcpbuilder.SetNoteInterval(count);
+ BUILDER_UNLOCK
+}
+
+int RTPSession::SetLocalName(const void *s,size_t len)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ int status;
+ BUILDER_LOCK
+ status = rtcpbuilder.SetLocalName(s,len);
+ BUILDER_UNLOCK
+ return status;
+}
+
+int RTPSession::SetLocalEMail(const void *s,size_t len)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ int status;
+ BUILDER_LOCK
+ status = rtcpbuilder.SetLocalEMail(s,len);
+ BUILDER_UNLOCK
+ return status;
+}
+
+int RTPSession::SetLocalLocation(const void *s,size_t len)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ int status;
+ BUILDER_LOCK
+ status = rtcpbuilder.SetLocalLocation(s,len);
+ BUILDER_UNLOCK
+ return status;
+}
+
+int RTPSession::SetLocalPhone(const void *s,size_t len)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ int status;
+ BUILDER_LOCK
+ status = rtcpbuilder.SetLocalPhone(s,len);
+ BUILDER_UNLOCK
+ return status;
+}
+
+int RTPSession::SetLocalTool(const void *s,size_t len)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ int status;
+ BUILDER_LOCK
+ status = rtcpbuilder.SetLocalTool(s,len);
+ BUILDER_UNLOCK
+ return status;
+}
+
+int RTPSession::SetLocalNote(const void *s,size_t len)
+{
+ if (!created)
+ return ERR_RTP_SESSION_NOTCREATED;
+
+ int status;
+ BUILDER_LOCK
+ status = rtcpbuilder.SetLocalNote(s,len);
+ BUILDER_UNLOCK
+ return status;
+}
+
+int RTPSession::ProcessPolledData()
+{
+ RTPRawPacket *rawpack;
+ int status;
+
+ SOURCES_LOCK
+ while ((rawpack = rtptrans->GetNextPacket()) != 0)
+ {
+ sources.ClearOwnCollisionFlag();
+
+ // since our sources instance also uses the scheduler (analysis of incoming packets)
+ // we'll lock it
+ SCHED_LOCK
+ if ((status = sources.ProcessRawPacket(rawpack,rtptrans,acceptownpackets)) < 0)
+ {
+ SCHED_UNLOCK
+ SOURCES_UNLOCK
+ RTPDelete(rawpack,GetMemoryManager());
+ return status;
+ }
+ SCHED_UNLOCK
+
+ if (sources.DetectedOwnCollision()) // collision handling!
+ {
+ bool created;
+
+ if ((status = collisionlist.UpdateAddress(rawpack->GetSenderAddress(),rawpack->GetReceiveTime(),&created)) < 0)
+ {
+ SOURCES_UNLOCK
+ RTPDelete(rawpack,GetMemoryManager());
+ return status;
+ }
+
+ if (created) // first time we've encountered this address, send bye packet and
+ { // change our own SSRC
+ PACKSENT_LOCK
+ bool hassentpackets = sentpackets;
+ PACKSENT_UNLOCK
+
+ if (hassentpackets)
+ {
+ // Only send BYE packet if we've actually sent data using this
+ // SSRC
+
+ RTCPCompoundPacket *rtcpcomppack;
+
+ BUILDER_LOCK
+ if ((status = rtcpbuilder.BuildBYEPacket(&rtcpcomppack,0,0,useSR_BYEifpossible)) < 0)
+ {
+ BUILDER_UNLOCK
+ SOURCES_UNLOCK
+ RTPDelete(rawpack,GetMemoryManager());
+ return status;
+ }
+ BUILDER_UNLOCK
+
+ byepackets.push_back(rtcpcomppack);
+ if (byepackets.size() == 1) // was the first packet, schedule a BYE packet (otherwise there's already one scheduled)
+ {
+ SCHED_LOCK
+ rtcpsched.ScheduleBYEPacket(rtcpcomppack->GetCompoundPacketLength());
+ SCHED_UNLOCK
+ }
+ }
+ // bye packet is built and scheduled, now change our SSRC
+ // and reset the packet count in the transmitter
+
+ BUILDER_LOCK
+ uint32_t newssrc = packetbuilder.CreateNewSSRC(sources);
+ BUILDER_UNLOCK
+
+ PACKSENT_LOCK
+ sentpackets = false;
+ PACKSENT_UNLOCK
+
+ // remove old entry in source table and add new one
+
+ if ((status = sources.DeleteOwnSSRC()) < 0)
+ {
+ SOURCES_UNLOCK
+ RTPDelete(rawpack,GetMemoryManager());
+ return status;
+ }
+ if ((status = sources.CreateOwnSSRC(newssrc)) < 0)
+ {
+ SOURCES_UNLOCK
+ RTPDelete(rawpack,GetMemoryManager());
+ return status;
+ }
+ }
+ }
+ RTPDelete(rawpack,GetMemoryManager());
+ }
+
+ SCHED_LOCK
+ RTPTime d = rtcpsched.CalculateDeterministicInterval(false);
+ SCHED_UNLOCK
+
+ RTPTime t = RTPTime::CurrentTime();
+ double Td = d.GetDouble();
+ RTPTime sendertimeout = RTPTime(Td*sendermultiplier);
+ RTPTime generaltimeout = RTPTime(Td*membermultiplier);
+ RTPTime byetimeout = RTPTime(Td*byemultiplier);
+ RTPTime colltimeout = RTPTime(Td*collisionmultiplier);
+ RTPTime notetimeout = RTPTime(Td*notemultiplier);
+
+ sources.MultipleTimeouts(t,sendertimeout,byetimeout,generaltimeout,notetimeout);
+ collisionlist.Timeout(t,colltimeout);
+
+ // We'll check if it's time for RTCP stuff
+
+ SCHED_LOCK
+ bool istime = rtcpsched.IsTime();
+ SCHED_UNLOCK
+
+ if (istime)
+ {
+ RTCPCompoundPacket *pack;
+
+ // we'll check if there's a bye packet to send, or just a normal packet
+
+ if (byepackets.empty())
+ {
+ BUILDER_LOCK
+ if ((status = rtcpbuilder.BuildNextPacket(&pack)) < 0)
+ {
+ BUILDER_UNLOCK
+ SOURCES_UNLOCK
+ return status;
+ }
+ BUILDER_UNLOCK
+ if ((status = rtptrans->SendRTCPData(pack->GetCompoundPacketData(),pack->GetCompoundPacketLength())) < 0)
+ {
+ SOURCES_UNLOCK
+ RTPDelete(pack,GetMemoryManager());
+ return status;
+ }
+
+ PACKSENT_LOCK
+ sentpackets = true;
+ PACKSENT_UNLOCK
+
+ OnSendRTCPCompoundPacket(pack); // we'll place this after the actual send to avoid tampering
+ }
+ else
+ {
+ pack = *(byepackets.begin());
+ byepackets.pop_front();
+
+ if ((status = rtptrans->SendRTCPData(pack->GetCompoundPacketData(),pack->GetCompoundPacketLength())) < 0)
+ {
+ SOURCES_UNLOCK
+ RTPDelete(pack,GetMemoryManager());
+ return status;
+ }
+
+ PACKSENT_LOCK
+ sentpackets = true;
+ PACKSENT_UNLOCK
+
+ OnSendRTCPCompoundPacket(pack); // we'll place this after the actual send to avoid tampering
+
+ if (!byepackets.empty()) // more bye packets to send, schedule them
+ {
+ SCHED_LOCK
+ rtcpsched.ScheduleBYEPacket((*(byepackets.begin()))->GetCompoundPacketLength());
+ SCHED_UNLOCK
+ }
+ }
+
+ SCHED_LOCK
+ rtcpsched.AnalyseOutgoing(*pack);
+ SCHED_UNLOCK
+
+ RTPDelete(pack,GetMemoryManager());
+ }
+ SOURCES_UNLOCK
+ return 0;
+}
+
+int RTPSession::CreateCNAME(uint8_t *buffer,size_t *bufferlength,bool resolve)
+{
+#ifndef WIN32
+ bool gotlogin = true;
+#ifdef RTP_SUPPORT_GETLOGINR
+ buffer[0] = 0;
+ if (getlogin_r((char *)buffer,*bufferlength) != 0)
+ gotlogin = false;
+ else
+ {
+ if (buffer[0] == 0)
+ gotlogin = false;
+ }
+
+ if (!gotlogin) // try regular getlogin
+ {
+ char *loginname = getlogin();
+ if (loginname == 0)
+ gotlogin = false;
+ else
+ strncpy((char *)buffer,loginname,*bufferlength);
+ }
+#else
+ char *loginname = getlogin();
+ if (loginname == 0)
+ gotlogin = false;
+ else
+ strncpy((char *)buffer,loginname,*bufferlength);
+#endif // RTP_SUPPORT_GETLOGINR
+ if (!gotlogin)
+ {
+ char *logname = getenv("LOGNAME");
+ if (logname == 0)
+ return ERR_RTP_SESSION_CANTGETLOGINNAME;
+ strncpy((char *)buffer,logname,*bufferlength);
+ }
+#else // Win32 version
+
+#ifndef _WIN32_WCE
+ DWORD len = *bufferlength;
+ if (!GetUserName((LPTSTR)buffer,&len))
+#if (defined(_MSC_VER) && _MSC_VER >= 1400 ) // Check if we can use the secure strncpy_s
+ strncpy_s((char *)buffer,*bufferlength,"unknown",_TRUNCATE);
+#else
+ strncpy((char *)buffer,"unknown",*bufferlength);
+#endif // Less secure version
+
+#else
+ strncpy((char *)buffer,"unknown",*bufferlength);
+#endif // _WIN32_WCE
+
+#endif // WIN32
+ buffer[*bufferlength-1] = 0;
+
+ size_t offset = strlen((const char *)buffer);
+ if (offset < (*bufferlength-1))
+ buffer[offset] = (uint8_t)'@';
+ offset++;
+
+ size_t buflen2 = *bufferlength-offset;
+ int status;
+
+ if (resolve)
+ {
+ if ((status = rtptrans->GetLocalHostName(buffer+offset,&buflen2)) < 0)
+ return status;
+ *bufferlength = buflen2+offset;
+ }
+ else
+ {
+ char hostname[1024];
+
+#if defined(WIN32) && !defined(_WIN32_WCE) && (defined(_MSC_VER) && _MSC_VER >= 1400 ) // Check if we can use the secure strncpy_s
+ strncpy_s(hostname,1024,"localhost",_TRUNCATE); // just in case gethostname fails
+#else
+ strncpy(hostname,"localhost",1024); // just in case gethostname fails
+#endif
+ gethostname(hostname,1024);
+#if defined(WIN32) && !defined(_WIN32_WCE) && (defined(_MSC_VER) && _MSC_VER >= 1400 ) // Check if we can use the secure strncpy_s
+ strncpy_s((char *)(buffer+offset),buflen2,hostname,_TRUNCATE);
+#else
+ strncpy((char *)(buffer+offset),hostname,buflen2);
+#endif
+ *bufferlength = offset+strlen(hostname);
+ }
+ if (*bufferlength > RTCP_SDES_MAXITEMLENGTH)
+ *bufferlength = RTCP_SDES_MAXITEMLENGTH;
+ return 0;
+}
+
+#ifdef RTPDEBUG
+void RTPSession::DumpSources()
+{
+ BeginDataAccess();
+ std::cout << "----------------------------------------------------------------" << std::endl;
+ sources.Dump();
+ EndDataAccess();
+}
+
+void RTPSession::DumpTransmitter()
+{
+ if (created)
+ rtptrans->Dump();
+}
+#endif // RTPDEBUG
+
diff --git a/src/rtpsession.h b/src/rtpsession.h
new file mode 100644
index 0000000..c962b2f
--- /dev/null
+++ b/src/rtpsession.h
@@ -0,0 +1,542 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpsession.h
+ */
+
+#ifndef RTPSESSION_H
+
+#define RTPSESSION_H
+
+#include "rtpconfig.h"
+#include "rtplibraryversion.h"
+#include "rtppacketbuilder.h"
+#include "rtpsessionsources.h"
+#include "rtptransmitter.h"
+#include "rtpcollisionlist.h"
+#include "rtcpscheduler.h"
+#include "rtcppacketbuilder.h"
+#include "rtptimeutilities.h"
+#include "rtcpcompoundpacketbuilder.h"
+#include "rtpmemoryobject.h"
+#include <list>
+
+#ifdef RTP_SUPPORT_THREAD
+ #include <jmutex.h>
+#endif // RTP_SUPPORT_THREAD
+
+class RTPTransmitter;
+class RTPSessionParams;
+class RTPTransmissionParams;
+class RTPAddress;
+class RTPSourceData;
+class RTPPacket;
+class RTPPollThread;
+class RTPTransmissionInfo;
+class RTCPCompoundPacket;
+class RTCPPacket;
+class RTCPAPPPacket;
+
+/** High level class for using RTP.
+ * For most RTP based applications, the RTPSession class will probably be the one to use. It handles
+ * the RTCP part completely internally, so the user can focus on sending and receiving the actual data.
+ * \note The RTPSession class is not meant to be thread safe. The user should use some kind of locking
+ * mechanism to prevent different threads from using the same RTPSession instance.
+ */
+class RTPSession : public RTPMemoryObject
+{
+public:
+ /** Constructs an RTPSession instance, optionally installing a memory manager. */
+ RTPSession(RTPMemoryManager *mgr = 0);
+ virtual ~RTPSession();
+
+ /** Creates an RTP session.
+ * This function creates an RTP session with parameters \c sessparams, which will use a transmitter
+ * corresponding to \c proto. Parameters for this transmitter can be specified as well. If \c
+ * proto is of type RTPTransmitter::UserDefinedProto, the NewUserDefinedTransmitter function must
+ * be implemented.
+ */
+ int Create(const RTPSessionParams &sessparams,const RTPTransmissionParams *transparams = 0, RTPTransmitter::TransmissionProtocol proto = RTPTransmitter::IPv4UDPProto);
+
+ /** Creates an RTP session using \c transmitter as transmission component.
+ * This function creates an RTP session with parameters \c sessparams, which will use the
+ * transmission component \c transmitter. Initialization and destruction of the transmitter
+ * will not be done by the RTPSession class if this Create function is used. This function
+ * can be useful if you which to reuse the transmission component in another RTPSession
+ * instance, once the original RTPSession isn't using the transmitter anymore.
+ */
+ int Create(const RTPSessionParams &sessparams,RTPTransmitter *transmitter);
+
+ /** Leaves the session without sending a BYE packet. */
+ void Destroy();
+
+ /** Sends a BYE packet and leaves the session.
+ * Sends a BYE packet and leaves the session. At most a time \c maxwaittime will be waited to
+ * send the BYE packet. If this time expires, the session will be left without sending a BYE packet.
+ * The BYE packet will contain as reason for leaving \c reason with length \c reasonlength.
+ */
+ void BYEDestroy(const RTPTime &maxwaittime,const void *reason,size_t reasonlength);
+
+ /** Returns whether the session has been created or not. */
+ bool IsActive();
+
+ /** Returns our own SSRC. */
+ uint32_t GetLocalSSRC();
+
+ /** Adds \c addr to the list of destinations. */
+ int AddDestination(const RTPAddress &addr);
+
+ /** Deletes \c addr from the list of destinations. */
+ int DeleteDestination(const RTPAddress &addr);
+
+ /** Clears the list of destinations. */
+ void ClearDestinations();
+
+ /** Returns \c true if multicasting is supported. */
+ bool SupportsMulticasting();
+
+ /** Joins the multicast group specified by \c addr. */
+ int JoinMulticastGroup(const RTPAddress &addr);
+
+ /** Leaves the multicast group specified by \c addr. */
+ int LeaveMulticastGroup(const RTPAddress &addr);
+
+ /** Leaves all multicast groups. */
+ void LeaveAllMulticastGroups();
+
+ /** Sends the RTP packet with payload \c data which has length \c len.
+ * Sends the RTP packet with payload \c data which has length \c len.
+ * The used payload type, marker and timestamp increment will be those that have been set
+ * using the \c SetDefault member functions.
+ */
+ int SendPacket(const void *data,size_t len);
+
+ /** Sends the RTP packet with payload \c data which has length \c len.
+ * It will use payload type \c pt, marker \c mark and after the packet has been built, the
+ * timestamp will be incremented by \c timestampinc.
+ */
+ int SendPacket(const void *data,size_t len,
+ uint8_t pt,bool mark,uint32_t timestampinc);
+
+ /** Sends the RTP packet with payload \c data which has length \c len.
+ * The packet will contain a header extension with identifier \c hdrextID and containing data
+ * \c hdrextdata. The length of this data is given by \c numhdrextwords and is specified in a
+ * number of 32-bit words. The used payload type, marker and timestamp increment will be those that
+ * have been set using the \c SetDefault member functions.
+ */
+ int SendPacketEx(const void *data,size_t len,
+ uint16_t hdrextID,const void *hdrextdata,size_t numhdrextwords);
+
+ /** Sends the RTP packet with payload \c data which has length \c len.
+ * It will use payload type \c pt, marker \c mark and after the packet has been built, the
+ * timestamp will be incremented by \c timestampinc. The packet will contain a header
+ * extension with identifier \c hdrextID and containing data \c hdrextdata. The length
+ * of this data is given by \c numhdrextwords and is specified in a number of 32-bit words.
+ */
+ int SendPacketEx(const void *data,size_t len,
+ uint8_t pt,bool mark,uint32_t timestampinc,
+ uint16_t hdrextID,const void *hdrextdata,size_t numhdrextwords);
+#ifdef RTP_SUPPORT_SENDAPP
+ /** If sending of RTCP APP packets was enabled at compile time, this function creates a compound packet
+ * containing an RTCP APP packet and sends it immediately.
+ * If sending of RTCP APP packets was enabled at compile time, this function creates a compound packet
+ * containing an RTCP APP packet and sends it immediately. If successful, the function returns the number
+ * of bytes in the RTCP compound packet. Note that this immediate sending is not compliant with the RTP
+ * specification, so use with care.
+ */
+ int SendRTCPAPPPacket(uint8_t subtype, const uint8_t name[4], const void *appdata, size_t appdatalen);
+#endif // RTP_SUPPORT_SENDAPP
+
+ /** Sets the default payload type for RTP packets to \c pt. */
+ int SetDefaultPayloadType(uint8_t pt);
+
+ /** Sets the default marker for RTP packets to \c m. */
+ int SetDefaultMark(bool m);
+
+ /** Sets the default value to increment the timestamp with to \c timestampinc. */
+ int SetDefaultTimestampIncrement(uint32_t timestampinc);
+
+ /** This function increments the timestamp with the amount given by \c inc.
+ * This function increments the timestamp with the amount given by \c inc. This can be useful
+ * if, for example, a packet was not sent because it contained only silence. Then, this function
+ * should be called to increment the timestamp with the appropriate amount so that the next packets
+ * will still be played at the correct time at other hosts.
+ */
+ int IncrementTimestamp(uint32_t inc);
+
+ /** This function increments the timestamp with the amount given set by the SetDefaultTimestampIncrement
+ * member function.
+ * This function increments the timestamp with the amount given set by the SetDefaultTimestampIncrement
+ * member function. This can be useful if, for example, a packet was not sent because it contained only silence.
+ * Then, this function should be called to increment the timestamp with the appropriate amount so that the next
+ * packets will still be played at the correct time at other hosts.
+ */
+ int IncrementTimestampDefault();
+
+ /** This function allows you to inform the library about the delay between sampling the first
+ * sample of a packet and sending the packet.
+ * This function allows you to inform the library about the delay between sampling the first
+ * sample of a packet and sending the packet. This delay is taken into account when calculating the
+ * relation between RTP timestamp and wallclock time, used for inter-media synchronization.
+ */
+ int SetPreTransmissionDelay(const RTPTime &delay);
+
+ /** This function returns an instance of a subclass of RTPTransmissionInfo which will give some
+ * additional information about the transmitter (a list of local IP addresses for example).
+ * This function returns an instance of a subclass of RTPTransmissionInfo which will give some
+ * additional information about the transmitter (a list of local IP addresses for example). The user
+ * has to free the returned instance when it is no longer needed, preferably using the DeleteTransmissionInfo
+ * function.
+ */
+ RTPTransmissionInfo *GetTransmissionInfo();
+
+ /** Frees the memory used by the transmission information \c inf. */
+ void DeleteTransmissionInfo(RTPTransmissionInfo *inf);
+
+ /** If you're not using the poll thread, this function must be called regularly to process incoming data
+ * and to send RTCP data when necessary.
+ */
+ int Poll();
+
+ /** Waits at most a time \c delay until incoming data has been detected.
+ * Waits at most a time \c delay until incoming data has been detected. Only works when you're not
+ * using the poll thread. If \c dataavailable is not \c NULL, it should be set to \c true if data
+ * was actually read and to \c false otherwise.
+ */
+ int WaitForIncomingData(const RTPTime &delay,bool *dataavailable = 0);
+
+ /** If the previous function has been called, this one aborts the waiting (only works when you're not
+ * using the poll thread).
+ */
+ int AbortWait();
+
+ /** Returns the time interval after which an RTCP compound packet may have to be sent (only works when
+ * you're not using the poll thread.
+ */
+ RTPTime GetRTCPDelay();
+
+ /** The following member functions (till EndDataAccess}) need to be accessed between a call
+ * to BeginDataAccess and EndDataAccess.
+ * The BeginDataAccess function makes sure that the poll thread won't access the source table
+ * at the same time that you're using it. When the EndDataAccess is called, the lock on the
+ * source table is freed again.
+ */
+ int BeginDataAccess();
+
+ /** Starts the iteration over the participants by going to the first member in the table.
+ * Starts the iteration over the participants by going to the first member in the table.
+ * If a member was found, the function returns \c true, otherwise it returns \c false.
+ */
+ bool GotoFirstSource();
+
+ /** Sets the current source to be the next source in the table.
+ * Sets the current source to be the next source in the table. If we're already at the last
+ * source, the function returns \c false, otherwise it returns \c true.
+ */
+ bool GotoNextSource();
+
+ /** Sets the current source to be the previous source in the table.
+ * Sets the current source to be the previous source in the table. If we're at the first source,
+ * the function returns \c false, otherwise it returns \c true.
+ */
+ bool GotoPreviousSource();
+
+ /** Sets the current source to be the first source in the table which has RTPPacket instances
+ * that we haven't extracted yet.
+ * Sets the current source to be the first source in the table which has RTPPacket instances
+ * that we haven't extracted yet. If no such member was found, the function returns \c false,
+ * otherwise it returns \c true.
+ */
+ bool GotoFirstSourceWithData();
+
+ /** Sets the current source to be the next source in the table which has RTPPacket instances
+ * that we haven't extracted yet.
+ * Sets the current source to be the next source in the table which has RTPPacket instances
+ * that we haven't extracted yet. If no such member was found, the function returns \c false,
+ * otherwise it returns \c true.
+ */
+ bool GotoNextSourceWithData();
+
+ /** Sets the current source to be the previous source in the table which has RTPPacket
+ * instances that we haven't extracted yet.
+ * Sets the current source to be the previous source in the table which has RTPPacket
+ * instances that we haven't extracted yet. If no such member was found, the function returns \c false,
+ * otherwise it returns \c true.
+ */
+ bool GotoPreviousSourceWithData();
+
+ /** Returns the \c RTPSourceData instance for the currently selected participant. */
+ RTPSourceData *GetCurrentSourceInfo();
+
+ /** Returns the \c RTPSourceData instance for the participant identified by \c ssrc,
+ * or NULL if no such entry exists.
+ */
+ RTPSourceData *GetSourceInfo(uint32_t ssrc);
+
+ /** Extracts the next packet from the received packets queue of the current participant,
+ * or NULL if no more packets are available.
+ * Extracts the next packet from the received packets queue of the current participant,
+ * or NULL if no more packets are available. When the packet is no longer needed, its
+ * memory should be freed using the DeletePacket member function.
+ */
+ RTPPacket *GetNextPacket();
+
+ /** Frees the memory used by \c p. */
+ void DeletePacket(RTPPacket *p);
+
+ /** See BeginDataAccess. */
+ int EndDataAccess();
+
+ /** Sets the receive mode to \c m.
+ * Sets the receive mode to \c m. Note that when the receive mode is changed, the list of
+ * addresses to be ignored ot accepted will be cleared.
+ */
+ int SetReceiveMode(RTPTransmitter::ReceiveMode m);
+
+ /** Adds \c addr to the list of addresses to ignore. */
+ int AddToIgnoreList(const RTPAddress &addr);
+
+ /** Deletes \c addr from the list of addresses to ignore. */
+ int DeleteFromIgnoreList(const RTPAddress &addr);
+
+ /** Clears the list of addresses to ignore. */
+ void ClearIgnoreList();
+
+ /** Adds \c addr to the list of addresses to accept. */
+ int AddToAcceptList(const RTPAddress &addr);
+
+ /** Deletes \c addr from the list of addresses to accept. */
+ int DeleteFromAcceptList(const RTPAddress &addr);
+
+ /** Clears the list of addresses to accept. */
+ void ClearAcceptList();
+
+ /** Sets the maximum allowed packet size to \c s. */
+ int SetMaximumPacketSize(size_t s);
+
+ /** Sets the session bandwidth to \c bw, which is specified in bytes per second. */
+ int SetSessionBandwidth(double bw);
+
+ /** Sets the timestamp unit for our own data.
+ * Sets the timestamp unit for our own data. The timestamp unit is defined as a time interval in
+ * seconds divided by the corresponding timestamp interval. For example, for 8000 Hz audio, the
+ * timestamp unit would typically be 1/8000. Since this value is initially set to an illegal value,
+ * the user must set this to an allowed value to be able to create a session.
+ */
+ int SetTimestampUnit(double u);
+
+ /** Sets the RTCP interval for the SDES name item.
+ * After all possible sources in the source table have been processed, the class will check if other
+ * SDES items need to be sent. If \c count is zero or negative, nothing will happen. If \c count
+ * is positive, an SDES name item will be added after the sources in the source table have been
+ * processed \c count times.
+ */
+ void SetNameInterval(int count);
+
+ /** Sets the RTCP interval for the SDES e-mail item.
+ * After all possible sources in the source table have been processed, the class will check if other
+ * SDES items need to be sent. If \c count is zero or negative, nothing will happen. If \c count
+ * is positive, an SDES e-mail item will be added after the sources in the source table have been
+ * processed \c count times.
+ */
+ void SetEMailInterval(int count);
+
+ /** Sets the RTCP interval for the SDES location item.
+ * After all possible sources in the source table have been processed, the class will check if other
+ * SDES items need to be sent. If \c count is zero or negative, nothing will happen. If \c count
+ * is positive, an SDES location item will be added after the sources in the source table have been
+ * processed \c count times.
+ */
+ void SetLocationInterval(int count);
+
+ /** Sets the RTCP interval for the SDES phone item.
+ * After all possible sources in the source table have been processed, the class will check if other
+ * SDES items need to be sent. If \c count is zero or negative, nothing will happen. If \c count
+ * is positive, an SDES phone item will be added after the sources in the source table have been
+ * processed \c count times.
+ */
+ void SetPhoneInterval(int count);
+
+ /** Sets the RTCP interval for the SDES tool item.
+ * After all possible sources in the source table have been processed, the class will check if other
+ * SDES items need to be sent. If \c count is zero or negative, nothing will happen. If \c count
+ * is positive, an SDES tool item will be added after the sources in the source table have been
+ * processed \c count times.
+ */
+ void SetToolInterval(int count);
+
+ /** Sets the RTCP interval for the SDES note item.
+ * After all possible sources in the source table have been processed, the class will check if other
+ * SDES items need to be sent. If \c count is zero or negative, nothing will happen. If \c count
+ * is positive, an SDES note item will be added after the sources in the source table have been
+ * processed \c count times.
+ */
+ void SetNoteInterval(int count);
+
+ /** Sets the SDES name item for the local participant to the value \c s with length \c len. */
+ int SetLocalName(const void *s,size_t len);
+
+ /** Sets the SDES e-mail item for the local participant to the value \c s with length \c len. */
+ int SetLocalEMail(const void *s,size_t len);
+
+ /** Sets the SDES location item for the local participant to the value \c s with length \c len. */
+ int SetLocalLocation(const void *s,size_t len);
+
+ /** Sets the SDES phone item for the local participant to the value \c s with length \c len. */
+ int SetLocalPhone(const void *s,size_t len);
+
+ /** Sets the SDES tool item for the local participant to the value \c s with length \c len. */
+ int SetLocalTool(const void *s,size_t len);
+
+ /** Sets the SDES note item for the local participant to the value \c s with length \c len. */
+ int SetLocalNote(const void *s,size_t len);
+
+#ifdef RTPDEBUG
+ void DumpSources();
+ void DumpTransmitter();
+#endif // RTPDEBUG
+protected:
+ /** Allocate a user defined transmitter.
+ * In case you specified in the Create function that you want to use a
+ * user defined transmitter, you should override this function. The RTPTransmitter
+ * instance returned by this function will then be used to send and receive RTP and
+ * RTCP packets. Note that when the session is destroyed, this RTPTransmitter
+ * instance will be destroyed as well.
+ */
+ virtual RTPTransmitter *NewUserDefinedTransmitter() { return 0; }
+
+ /** Is called when an incoming RTCP packet is about to be processed. */
+ virtual void OnRTPPacket(RTPPacket *pack,const RTPTime &receivetime,
+ const RTPAddress *senderaddress) { }
+
+ /** Is called when an incoming RTCP packet is about to be processed. */
+ virtual void OnRTCPCompoundPacket(RTCPCompoundPacket *pack,const RTPTime &receivetime,
+ const RTPAddress *senderaddress) { }
+
+ /** Is called when an SSRC collision was detected.
+ * Is called when an SSRC collision was detected. The instance \c srcdat is the one present in
+ * the table, the address \c senderaddress is the one that collided with one of the addresses
+ * and \c isrtp indicates against which address of \c srcdat the check failed.
+ */
+ virtual void OnSSRCCollision(RTPSourceData *srcdat,const RTPAddress *senderaddress,bool isrtp) { }
+
+ /** Is called when another CNAME was received than the one already present for source \c srcdat. */
+ virtual void OnCNAMECollision(RTPSourceData *srcdat,const RTPAddress *senderaddress,
+ const uint8_t *cname,size_t cnamelength) { }
+
+ /** Is called when a new entry \c srcdat is added to the source table. */
+ virtual void OnNewSource(RTPSourceData *srcdat) { }
+
+ /** Is called when the entry \c srcdat is about to be deleted from the source table. */
+ virtual void OnRemoveSource(RTPSourceData *srcdat) { }
+
+ /** Is called when participant \c srcdat is timed out. */
+ virtual void OnTimeout(RTPSourceData *srcdat) { }
+
+ /** Is called when participant \c srcdat is timed after having sent a BYE packet. */
+ virtual void OnBYETimeout(RTPSourceData *srcdat) { }
+
+ /** Is called when an RTCP APP packet \c apppacket has been received at time \c receivetime
+ * from address \c senderaddress.
+ */
+ virtual void OnAPPPacket(RTCPAPPPacket *apppacket,const RTPTime &receivetime,
+ const RTPAddress *senderaddress) { }
+
+ /** Is called when an unknown RTCP packet type was detected. */
+ virtual void OnUnknownPacketType(RTCPPacket *rtcppack,const RTPTime &receivetime,
+ const RTPAddress *senderaddress) { }
+
+ /** Is called when an unknown packet format for a known packet type was detected. */
+ virtual void OnUnknownPacketFormat(RTCPPacket *rtcppack,const RTPTime &receivetime,
+ const RTPAddress *senderaddress) { }
+
+ /** Is called when the SDES NOTE item for source \c srcdat has been timed out. */
+ virtual void OnNoteTimeout(RTPSourceData *srcdat) { }
+
+ /** Is called when a BYE packet has been processed for source \c srcdat. */
+ virtual void OnBYEPacket(RTPSourceData *srcdat) { }
+
+ /** Is called when an RTCP compound packet has just been sent (useful to inspect outgoing RTCP data). */
+ virtual void OnSendRTCPCompoundPacket(RTCPCompoundPacket *pack) { }
+#ifdef RTP_SUPPORT_THREAD
+ /** Is called when error \c errcode was detected in the poll thread. */
+ virtual void OnPollThreadError(int errcode) { }
+
+ /** Is called each time the poll thread loops.
+ * Is called each time the poll thread loops. This happens when incoming data was
+ * detected or when it's time to send an RTCP compound packet.
+ */
+ virtual void OnPollThreadStep() { }
+#endif // RTP_SUPPORT_THREAD
+private:
+ int InternalCreate(const RTPSessionParams &sessparams);
+ int CreateCNAME(uint8_t *buffer,size_t *bufferlength,bool resolve);
+ int ProcessPolledData();
+ int ProcessRTCPCompoundPacket(RTCPCompoundPacket &rtcpcomppack,RTPRawPacket *pack);
+
+ RTPTransmitter *rtptrans;
+ bool created;
+ bool deletetransmitter;
+ bool usingpollthread;
+ bool acceptownpackets;
+ bool useSR_BYEifpossible;
+ size_t maxpacksize;
+ double sessionbandwidth;
+ double controlfragment;
+ double sendermultiplier;
+ double byemultiplier;
+ double membermultiplier;
+ double collisionmultiplier;
+ double notemultiplier;
+ bool sentpackets;
+
+ RTPSessionSources sources;
+ RTPPacketBuilder packetbuilder;
+ RTCPScheduler rtcpsched;
+ RTCPPacketBuilder rtcpbuilder;
+ RTPCollisionList collisionlist;
+
+ std::list<RTCPCompoundPacket *> byepackets;
+
+#ifdef RTP_SUPPORT_THREAD
+ RTPPollThread *pollthread;
+ JMutex sourcesmutex,buildermutex,schedmutex,packsentmutex;
+
+ friend class RTPPollThread;
+#endif // RTP_SUPPORT_THREAD
+ friend class RTPSessionSources;
+ friend class RTCPSessionPacketBuilder;
+};
+
+#endif // RTPSESSION_H
+
diff --git a/src/rtpsessionparams.cpp b/src/rtpsessionparams.cpp
new file mode 100644
index 0000000..b6ffab5
--- /dev/null
+++ b/src/rtpsessionparams.cpp
@@ -0,0 +1,80 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtpconfig.h"
+#include "rtpsessionparams.h"
+#include "rtpdefines.h"
+#include "rtperrors.h"
+
+#include "rtpdebug.h"
+
+RTPSessionParams::RTPSessionParams() : mininterval(0,0)
+{
+#ifdef RTP_SUPPORT_THREAD
+ usepollthread = true;
+#else
+ usepollthread = false;
+#endif // RTP_SUPPORT_THREAD
+ maxpacksize = RTP_DEFAULTPACKETSIZE;
+ receivemode = RTPTransmitter::AcceptAll;
+ acceptown = false;
+ owntsunit = -1; // The user will have to set it to the correct value himself
+ resolvehostname = false;
+#ifdef RTP_SUPPORT_PROBATION
+ probationtype = RTPSources::ProbationStore;
+#endif // RTP_SUPPORT_PROBATION
+
+ mininterval = RTPTime(RTCP_DEFAULTMININTERVAL);
+ sessionbandwidth = RTP_DEFAULTSESSIONBANDWIDTH;
+ controlfrac = RTCP_DEFAULTBANDWIDTHFRACTION;
+ senderfrac = RTCP_DEFAULTSENDERFRACTION;
+ usehalfatstartup = RTCP_DEFAULTHALFATSTARTUP;
+ immediatebye = RTCP_DEFAULTIMMEDIATEBYE;
+ SR_BYE = RTCP_DEFAULTSRBYE;
+
+ sendermultiplier = RTP_SENDERTIMEOUTMULTIPLIER;
+ generaltimeoutmultiplier = RTP_MEMBERTIMEOUTMULTIPLIER;
+ byetimeoutmultiplier = RTP_BYETIMEOUTMULTIPLIER;
+ collisionmultiplier = RTP_COLLISIONTIMEOUTMULTIPLIER;
+ notemultiplier = RTP_NOTETTIMEOUTMULTIPLIER;
+}
+
+int RTPSessionParams::SetUsePollThread(bool usethread)
+{
+#ifndef RTP_SUPPORT_THREAD
+ return ERR_RTP_NOTHREADSUPPORT;
+#else
+ usepollthread = usethread;
+ return 0;
+#endif // RTP_SUPPORT_THREAD
+}
+
diff --git a/src/rtpsessionparams.h b/src/rtpsessionparams.h
new file mode 100644
index 0000000..1e65bda
--- /dev/null
+++ b/src/rtpsessionparams.h
@@ -0,0 +1,220 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpsessionparams.h
+ */
+
+#ifndef RTPSESSIONPARAMS_H
+
+#define RTPSESSIONPARAMS_H
+
+#include "rtpconfig.h"
+#include "rtptypes.h"
+#include "rtptransmitter.h"
+#include "rtptimeutilities.h"
+#include "rtpsources.h"
+
+/** Describes the parameters for to be used by an RTPSession instance.
+ * Describes the parameters for to be used by an RTPSession instance. Note that the own timestamp
+ * unit must be set to a valid number, otherwise the session can't be created.
+ */
+class RTPSessionParams
+{
+public:
+ RTPSessionParams();
+
+ /** If \c usethread is \c true, the session will use a poll thread to automatically process incoming
+ * data and to send RTCP packets when necessary.
+ */
+ int SetUsePollThread(bool usethread);
+
+ /** Returns whether the session should use a poll thread or not (default is \c true). */
+ bool IsUsingPollThread() const { return usepollthread; }
+
+ /** Sets the maximum allowed packet size for the session. */
+ void SetMaximumPacketSize(size_t max) { maxpacksize = max; }
+
+ /** Returns the maximum allowed packet size (default is 1400 bytes). */
+ size_t GetMaximumPacketSize() const { return maxpacksize; }
+
+ /** If the argument is \c true, the session should accept its own packets and store
+ * them accordingly in the source table.
+ */
+ void SetAcceptOwnPackets(bool accept) { acceptown = accept; }
+
+ /** Returns \c true if the session should accept its own packets (default is \c false). */
+ bool AcceptOwnPackets() const { return acceptown; }
+
+ /** Sets the receive mode to be used by the session. */
+ void SetReceiveMode(RTPTransmitter::ReceiveMode recvmode) { receivemode = recvmode; }
+
+ /** Sets the receive mode to be used by the session (default is: accept all packets). */
+ RTPTransmitter::ReceiveMode GetReceiveMode() const { return receivemode; }
+
+ /** Sets the timestamp unit for our own data.
+ * Sets the timestamp unit for our own data. The timestamp unit is defined as a time interval in
+ * seconds divided by the corresponding timestamp interval. For example, for 8000 Hz audio, the
+ * timestamp unit would typically be 1/8000. Since this value is initially set to an illegal value,
+ * the user must set this to an allowed value to be able to create a session.
+ */
+ void SetOwnTimestampUnit(double tsunit) { owntsunit = tsunit; }
+
+ /** Returns the currently set timestamp unit. */
+ double GetOwnTimestampUnit() const { return owntsunit; }
+
+ /** Sets a flag indicating if a DNS lookup should be done to determine our hostname (to construct a CNAME item).
+ * If \c v is set to \c true, the session will ask the transmitter to find a host name based upon the IP
+ * addresses in its list of local IP addresses. If set to \c false, a call to \c gethostname or something
+ * similar will be used to find the local hostname. Note that the first method might take some time.
+ */
+ void SetResolveLocalHostname(bool v) { resolvehostname = v; }
+
+ /** Returns whether the local hostname should be determined from the transmitter's list of local IP addresses
+ * or not (default is \c false).
+ */
+ bool GetResolveLocalHostname() const { return resolvehostname; }
+#ifdef RTP_SUPPORT_PROBATION
+ /** If probation support is enabled, this function sets the probation type to be used. */
+ void SetProbationType(RTPSources::ProbationType probtype) { probationtype = probtype; }
+
+ /** Returns the probation type which will be used (default is RTPSources::ProbationStore). */
+ RTPSources::ProbationType GetProbationType() const { return probationtype; }
+#endif // RTP_SUPPORT_PROBATION
+
+ /** Sets the session bandwidth in bytes per second. */
+ void SetSessionBandwidth(double sessbw) { sessionbandwidth = sessbw; }
+
+ /** Returns the session bandwidth in bytes per second (default is 10000 bytes per second). */
+ double GetSessionBandwidth() const { return sessionbandwidth; }
+
+ /** Sets the fraction of the session bandwidth to be used for control traffic. */
+ void SetControlTrafficFraction(double frac) { controlfrac = frac; }
+
+ /** Returns the fraction of the session bandwidth that will be used for control traffic (default is 5%). */
+ double GetControlTrafficFraction() const { return controlfrac; }
+
+ /** Sets the minimum fraction of the control traffic that will be used by senders. */
+ void SetSenderControlBandwidthFraction(double frac) { senderfrac = frac; }
+
+ /** Returns the minimum fraction of the control traffic that will be used by senders (default is 25%). */
+ double GetSenderControlBandwidthFraction() const { return senderfrac; }
+
+ /** Set the minimal time interval between sending RTCP packets. */
+ void SetMinimumRTCPTransmissionInterval(const RTPTime &t) { mininterval = t; }
+
+ /** Returns the minimal time interval between sending RTCP packets (default is 5 seconds). */
+ RTPTime GetMinimumRTCPTransmissionInterval() const { return mininterval; }
+
+ /** If \c usehalf is set to \c true, the session will only wait half of the calculated RTCP
+ * interval before sending its first RTCP packet.
+ */
+ void SetUseHalfRTCPIntervalAtStartup(bool usehalf) { usehalfatstartup = usehalf; }
+
+ /** Returns whether the session will only wait half of the calculated RTCP interval before sending its
+ * first RTCP packet or not (default is \c true).
+ */
+ bool GetUseHalfRTCPIntervalAtStartup() const { return usehalfatstartup; }
+
+ /** If \c v is \c true, the session will send a BYE packet immediately if this is allowed. */
+ void SetRequestImmediateBYE(bool v) { immediatebye = v; }
+
+ /** Returns whether the session should send a BYE packet immediately (if allowed) or not (default is \c true). */
+ bool GetRequestImmediateBYE() const { return immediatebye; }
+
+ /** When sending a BYE packet, this indicates whether it will be part of an RTCP compound packet
+ * that begins with a sender report (if allowed) or a receiver report.
+ */
+ void SetSenderReportForBYE(bool v) { SR_BYE = v; }
+
+ /** Returns \c true if a BYE packet will be sent in an RTCP compound packet which starts with a
+ * sender report; if a receiver report will be used, the function returns \c false (default is \c true).
+ */
+ bool GetSenderReportForBYE() const { return SR_BYE; }
+
+ /** Sets the multiplier to be used when timing out senders. */
+ void SetSenderTimeoutMultiplier(double m) { sendermultiplier = m; }
+
+ /** Returns the multiplier to be used when timing out senders (default is 2). */
+ double GetSenderTimeoutMultiplier() const { return sendermultiplier; }
+
+ /** Sets the multiplier to be used when timing out members. */
+ void SetSourceTimeoutMultiplier(double m) { generaltimeoutmultiplier = m; }
+
+ /** Returns the multiplier to be used when timing out members (default is 5). */
+ double GetSourceTimeoutMultiplier() const { return generaltimeoutmultiplier; }
+
+ /** Sets the multiplier to be used when timing out a member after it has sent a BYE packet. */
+ void SetBYETimeoutMultiplier(double m) { byetimeoutmultiplier = m; }
+
+ /** Returns the multiplier to be used when timing out a member after it has sent a BYE packet (default is 1). */
+ double GetBYETimeoutMultiplier() const { return byetimeoutmultiplier; }
+
+ /** Sets the multiplier to be used when timing out entries in the collision table. */
+ void SetCollisionTimeoutMultiplier(double m) { collisionmultiplier = m; }
+
+ /** Returns the multiplier to be used when timing out entries in the collision table (default is 10). */
+ double GetCollisionTimeoutMultiplier() const { return collisionmultiplier; }
+
+ /** Sets the multiplier to be used when timing out SDES NOTE information. */
+ void SetNoteTimeoutMultiplier(double m) { notemultiplier = m; }
+
+ /** Returns the multiplier to be used when timing out SDES NOTE information (default is 25). */
+ double GetNoteTimeoutMultiplier() const { return notemultiplier; }
+private:
+ bool acceptown;
+ bool usepollthread;
+ size_t maxpacksize;
+ double owntsunit;
+ RTPTransmitter::ReceiveMode receivemode;
+ bool resolvehostname;
+#ifdef RTP_SUPPORT_PROBATION
+ RTPSources::ProbationType probationtype;
+#endif // RTP_SUPPORT_PROBATION
+
+ double sessionbandwidth;
+ double controlfrac;
+ double senderfrac;
+ RTPTime mininterval;
+ bool usehalfatstartup;
+ bool immediatebye;
+ bool SR_BYE;
+
+ double sendermultiplier;
+ double generaltimeoutmultiplier;
+ double byetimeoutmultiplier;
+ double collisionmultiplier;
+ double notemultiplier;
+};
+
+#endif // RTPSESSIONPARAMS_H
+
diff --git a/src/rtpsessionsources.cpp b/src/rtpsessionsources.cpp
new file mode 100644
index 0000000..6a6e5f6
--- /dev/null
+++ b/src/rtpsessionsources.cpp
@@ -0,0 +1,109 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtpsessionsources.h"
+#include "rtpsession.h"
+#include "rtpsourcedata.h"
+
+#include "rtpdebug.h"
+
+void RTPSessionSources::OnRTPPacket(RTPPacket *pack,const RTPTime &receivetime,const RTPAddress *senderaddress)
+{
+ rtpsession.OnRTPPacket(pack,receivetime,senderaddress);
+}
+
+void RTPSessionSources::OnRTCPCompoundPacket(RTCPCompoundPacket *pack,const RTPTime &receivetime,const RTPAddress *senderaddress)
+{
+ if (senderaddress != 0) // don't analyse own RTCP packets again (they're already analysed on their way out)
+ rtpsession.rtcpsched.AnalyseIncoming(*pack);
+ rtpsession.OnRTCPCompoundPacket(pack,receivetime,senderaddress);
+}
+
+void RTPSessionSources::OnSSRCCollision(RTPSourceData *srcdat,const RTPAddress *senderaddress,bool isrtp)
+{
+ if (srcdat->IsOwnSSRC())
+ owncollision = true;
+ rtpsession.OnSSRCCollision(srcdat,senderaddress,isrtp);
+}
+
+void RTPSessionSources::OnCNAMECollision(RTPSourceData *srcdat,const RTPAddress *senderaddress,const uint8_t *cname,size_t cnamelength)
+{
+ rtpsession.OnCNAMECollision(srcdat,senderaddress,cname,cnamelength);
+}
+
+void RTPSessionSources::OnNewSource(RTPSourceData *srcdat)
+{
+ rtpsession.OnNewSource(srcdat);
+}
+
+void RTPSessionSources::OnRemoveSource(RTPSourceData *srcdat)
+{
+ rtpsession.OnRemoveSource(srcdat);
+}
+
+void RTPSessionSources::OnTimeout(RTPSourceData *srcdat)
+{
+ rtpsession.rtcpsched.ActiveMemberDecrease();
+ rtpsession.OnTimeout(srcdat);
+}
+
+void RTPSessionSources::OnBYETimeout(RTPSourceData *srcdat)
+{
+ rtpsession.OnBYETimeout(srcdat);
+}
+
+void RTPSessionSources::OnBYEPacket(RTPSourceData *srcdat)
+{
+ rtpsession.rtcpsched.ActiveMemberDecrease();
+ rtpsession.OnBYEPacket(srcdat);
+}
+
+void RTPSessionSources::OnAPPPacket(RTCPAPPPacket *apppacket,const RTPTime &receivetime,const RTPAddress *senderaddress)
+{
+ rtpsession.OnAPPPacket(apppacket,receivetime,senderaddress);
+}
+
+void RTPSessionSources::OnUnknownPacketType(RTCPPacket *rtcppack,const RTPTime &receivetime, const RTPAddress *senderaddress)
+{
+ rtpsession.OnUnknownPacketType(rtcppack,receivetime,senderaddress);
+}
+
+void RTPSessionSources::OnUnknownPacketFormat(RTCPPacket *rtcppack,const RTPTime &receivetime,const RTPAddress *senderaddress)
+{
+ rtpsession.OnUnknownPacketFormat(rtcppack,receivetime,senderaddress);
+}
+
+void RTPSessionSources::OnNoteTimeout(RTPSourceData *srcdat)
+{
+ rtpsession.OnNoteTimeout(srcdat);
+}
+
diff --git a/src/rtpsessionsources.h b/src/rtpsessionsources.h
new file mode 100644
index 0000000..ad5a52b
--- /dev/null
+++ b/src/rtpsessionsources.h
@@ -0,0 +1,79 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpsessionsources.h
+ */
+
+#ifndef RTPSESSIONSOURCES_H
+
+#define RTPSESSIONSOURCES_H
+
+#include "rtpconfig.h"
+#include "rtpsources.h"
+
+class RTPSession;
+
+class RTPSessionSources : public RTPSources
+{
+public:
+ RTPSessionSources(RTPSession &sess,RTPMemoryManager *mgr) : RTPSources(RTPSources::ProbationStore,mgr),rtpsession(sess)
+ { owncollision = false; }
+ ~RTPSessionSources() { }
+ void ClearOwnCollisionFlag() { owncollision = false; }
+ bool DetectedOwnCollision() const { return owncollision; }
+private:
+ void OnRTPPacket(RTPPacket *pack,const RTPTime &receivetime,
+ const RTPAddress *senderaddress);
+ void OnRTCPCompoundPacket(RTCPCompoundPacket *pack,const RTPTime &receivetime,
+ const RTPAddress *senderaddress);
+ void OnSSRCCollision(RTPSourceData *srcdat,const RTPAddress *senderaddress,bool isrtp);
+ void OnCNAMECollision(RTPSourceData *srcdat,const RTPAddress *senderaddress,
+ const uint8_t *cname,size_t cnamelength);
+ void OnNewSource(RTPSourceData *srcdat);
+ void OnRemoveSource(RTPSourceData *srcdat);
+ void OnTimeout(RTPSourceData *srcdat);
+ void OnBYETimeout(RTPSourceData *srcdat);
+ void OnBYEPacket(RTPSourceData *srcdat);
+ void OnAPPPacket(RTCPAPPPacket *apppacket,const RTPTime &receivetime,
+ const RTPAddress *senderaddress);
+ void OnUnknownPacketType(RTCPPacket *rtcppack,const RTPTime &receivetime,
+ const RTPAddress *senderaddress);
+ void OnUnknownPacketFormat(RTCPPacket *rtcppack,const RTPTime &receivetime,
+ const RTPAddress *senderaddress);
+ void OnNoteTimeout(RTPSourceData *srcdat);
+
+ RTPSession &rtpsession;
+ bool owncollision;
+};
+
+#endif // RTPSESSIONSOURCES_H
diff --git a/src/rtpsourcedata.cpp b/src/rtpsourcedata.cpp
new file mode 100644
index 0000000..3ed5ad3
--- /dev/null
+++ b/src/rtpsourcedata.cpp
@@ -0,0 +1,446 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtpsourcedata.h"
+#include "rtpdefines.h"
+#include "rtpaddress.h"
+#include "rtpmemorymanager.h"
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ #include <netinet/in.h>
+#endif // WIN32
+
+#ifdef RTPDEBUG
+ #include <iostream>
+ #include <string>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+#define ACCEPTPACKETCODE \
+ *accept = true; \
+ \
+ sentdata = true; \
+ packetsreceived++; \
+ numnewpackets++; \
+ \
+ if (pack->GetExtendedSequenceNumber() == 0) \
+ { \
+ baseseqnr = 0x0000FFFF; \
+ numcycles = 0x00010000; \
+ } \
+ else \
+ baseseqnr = pack->GetExtendedSequenceNumber() - 1; \
+ \
+ exthighseqnr = baseseqnr + 1; \
+ prevpacktime = receivetime; \
+ prevexthighseqnr = baseseqnr; \
+ savedextseqnr = baseseqnr; \
+ \
+ pack->SetExtendedSequenceNumber(exthighseqnr); \
+ \
+ prevtimestamp = pack->GetTimestamp(); \
+ lastmsgtime = prevpacktime; \
+ if (!ownpacket) /* for own packet, this value is set on an outgoing packet */ \
+ lastrtptime = prevpacktime;
+
+void RTPSourceStats::ProcessPacket(RTPPacket *pack,const RTPTime &receivetime,double tsunit,
+ bool ownpacket,bool *accept,bool applyprobation,bool *onprobation)
+{
+ // Note that the sequence number in the RTP packet is still just the
+ // 16 bit number contained in the RTP header
+
+ *onprobation = false;
+
+ if (!sentdata) // no valid packets received yet
+ {
+#ifdef RTP_SUPPORT_PROBATION
+ if (applyprobation)
+ {
+ bool acceptpack = false;
+
+ if (probation)
+ {
+ uint16_t pseq;
+ uint32_t pseq2;
+
+ pseq = prevseqnr;
+ pseq++;
+ pseq2 = (uint32_t)pseq;
+ if (pseq2 == pack->GetExtendedSequenceNumber()) // ok, its the next expected packet
+ {
+ prevseqnr = (uint16_t)pack->GetExtendedSequenceNumber();
+ probation--;
+ if (probation == 0) // probation over
+ acceptpack = true;
+ else
+ *onprobation = true;
+ }
+ else // not next packet
+ {
+ probation = RTP_PROBATIONCOUNT;
+ prevseqnr = (uint16_t)pack->GetExtendedSequenceNumber();
+ *onprobation = true;
+ }
+ }
+ else // first packet received with this SSRC ID, start probation
+ {
+ probation = RTP_PROBATIONCOUNT;
+ prevseqnr = (uint16_t)pack->GetExtendedSequenceNumber();
+ *onprobation = true;
+ }
+
+ if (acceptpack)
+ {
+ ACCEPTPACKETCODE
+ }
+ else
+ {
+ *accept = false;
+ lastmsgtime = receivetime;
+ }
+ }
+ else // No probation
+ {
+ ACCEPTPACKETCODE
+ }
+#else // No compiled-in probation support
+
+ ACCEPTPACKETCODE
+
+#endif // RTP_SUPPORT_PROBATION
+ }
+ else // already got packets
+ {
+ uint16_t maxseq16;
+ uint32_t extseqnr;
+
+ // Adjust max extended sequence number and set extende seq nr of packet
+
+ *accept = true;
+ packetsreceived++;
+ numnewpackets++;
+
+ maxseq16 = (uint16_t)(exthighseqnr&0x0000FFFF);
+ if (pack->GetExtendedSequenceNumber() >= maxseq16)
+ {
+ extseqnr = numcycles+pack->GetExtendedSequenceNumber();
+ exthighseqnr = extseqnr;
+ }
+ else
+ {
+ uint16_t dif1,dif2;
+
+ dif1 = ((uint16_t)pack->GetExtendedSequenceNumber());
+ dif1 -= maxseq16;
+ dif2 = maxseq16;
+ dif2 -= ((uint16_t)pack->GetExtendedSequenceNumber());
+ if (dif1 < dif2)
+ {
+ numcycles += 0x00010000;
+ extseqnr = numcycles+pack->GetExtendedSequenceNumber();
+ exthighseqnr = extseqnr;
+ }
+ else
+ extseqnr = numcycles+pack->GetExtendedSequenceNumber();
+ }
+
+ pack->SetExtendedSequenceNumber(extseqnr);
+
+ // Calculate jitter
+
+ if (tsunit > 0)
+ {
+ RTPTime curtime = receivetime;
+ double diffts1,diffts2,diff;
+
+ curtime -= prevpacktime;
+ diffts1 = curtime.GetDouble()/tsunit;
+ diffts2 = (double)pack->GetTimestamp() - (double)prevtimestamp;
+ diff = diffts1 - diffts2;
+ if (diff < 0)
+ diff = -diff;
+ diff -= djitter;
+ diff /= 16.0;
+ djitter += diff;
+ jitter = (uint32_t)djitter;
+ }
+ else
+ {
+ djitter = 0;
+ jitter = 0;
+ }
+
+ prevpacktime = receivetime;
+ prevtimestamp = pack->GetTimestamp();
+ lastmsgtime = prevpacktime;
+ if (!ownpacket) // for own packet, this value is set on an outgoing packet
+ lastrtptime = prevpacktime;
+ }
+}
+
+RTPSourceData::RTPSourceData(uint32_t s, RTPMemoryManager *mgr) : RTPMemoryObject(mgr),SDESinf(mgr),byetime(0,0)
+{
+ ssrc = s;
+ issender = false;
+ iscsrc = false;
+ timestampunit = -1;
+ receivedbye = false;
+ byereason = 0;
+ byereasonlen = 0;
+ rtpaddr = 0;
+ rtcpaddr = 0;
+ ownssrc = false;
+ validated = false;
+ processedinrtcp = false;
+ isrtpaddrset = false;
+ isrtcpaddrset = false;
+}
+
+RTPSourceData::~RTPSourceData()
+{
+ FlushPackets();
+ if (byereason)
+ RTPDeleteByteArray(byereason,GetMemoryManager());
+ if (rtpaddr)
+ RTPDelete(rtpaddr,GetMemoryManager());
+ if (rtcpaddr)
+ RTPDelete(rtcpaddr,GetMemoryManager());
+}
+
+double RTPSourceData::INF_GetEstimatedTimestampUnit() const
+{
+ if (!SRprevinf.HasInfo())
+ return -1.0;
+
+ RTPTime t1 = RTPTime(SRinf.GetNTPTimestamp());
+ RTPTime t2 = RTPTime(SRprevinf.GetNTPTimestamp());
+ if ((t1.GetSeconds() == 0 && t1.GetMicroSeconds() == 0) ||
+ (t2.GetSeconds() == 0 && t2.GetMicroSeconds() == 0)) // one of the times couldn't be calculated
+ return -1.0;
+
+ if (t1 < t2)
+ return -1.0;
+
+ t1 -= t2; // get the time difference
+
+ uint32_t tsdiff = SRinf.GetRTPTimestamp()-SRprevinf.GetRTPTimestamp();
+
+ return (t1.GetDouble()/((double)tsdiff));
+}
+
+RTPTime RTPSourceData::INF_GetRoundtripTime() const
+{
+ if (!RRinf.HasInfo())
+ return RTPTime(0,0);
+ if (RRinf.GetDelaySinceLastSR() == 0 && RRinf.GetLastSRTimestamp() == 0)
+ return RTPTime(0,0);
+
+ RTPNTPTime recvtime = RRinf.GetReceiveTime().GetNTPTime();
+ uint32_t rtt = ((recvtime.GetMSW()&0xFFFF)<<16)|((recvtime.GetLSW()>>16)&0xFFFF);
+ rtt -= RRinf.GetLastSRTimestamp();
+ rtt -= RRinf.GetDelaySinceLastSR();
+
+ double drtt = (((double)rtt)/65536.0);
+ return RTPTime(drtt);
+}
+
+#ifdef RTPDEBUG
+void RTPSourceData::Dump()
+{
+ std::cout << "Source data for SSRC: " << ssrc << std::endl;
+ std::cout << " Active: " << ((IsActive())?"Yes":"No") << std::endl;
+ std::cout << " Sender: " << ((issender)?"Yes":"No") << std::endl;
+ std::cout << " CSRC: " << ((iscsrc)?"Yes":"No") << std::endl;
+ std::cout << " Received bye: " << ((receivedbye)?"Yes":"No") << std::endl;
+ std::cout << " ProcessedInRTCP: " << ((processedinrtcp)?"Yes":"No") << std::endl;
+ std::cout << " Timestamp unit: " << timestampunit << std::endl;
+ std::cout << " RTP address: ";
+ if (!isrtpaddrset)
+ std::cout << "Not set" << std::endl;
+ else
+ {
+ if (rtpaddr == 0)
+ std::cout << "Own session" << std::endl;
+ else
+ std::cout << rtpaddr->GetAddressString() << std::endl;
+ }
+ std::cout << " RTCP address: ";
+ if (!isrtcpaddrset)
+ std::cout << "Not set" << std::endl;
+ else
+ {
+ if (rtcpaddr == 0)
+ std::cout << "Own session" << std::endl;
+ else
+ std::cout << rtcpaddr->GetAddressString() << std::endl;
+ }
+ if (SRinf.HasInfo())
+ {
+ if (!SRprevinf.HasInfo())
+ {
+ std::cout << " SR Info:" << std::endl;
+ std::cout << " NTP timestamp: " << SRinf.GetNTPTimestamp().GetMSW() << ":" << SRinf.GetNTPTimestamp().GetLSW() << std::endl;
+ std::cout << " RTP timestamp: " << SRinf.GetRTPTimestamp() << std::endl;
+ std::cout << " Packet count: " << SRinf.GetPacketCount() << std::endl;
+ std::cout << " Octet count: " << SRinf.GetByteCount() << std::endl;
+ std::cout << " Receive time: " << SRinf.GetReceiveTime().GetSeconds() << std::endl;
+ }
+ else
+ {
+ std::cout << " SR Info:" << std::endl;
+ std::cout << " NTP timestamp: " << SRinf.GetNTPTimestamp().GetMSW() << ":" << SRinf.GetNTPTimestamp().GetLSW()
+ << " (" << SRprevinf.GetNTPTimestamp().GetMSW() << ":" << SRprevinf.GetNTPTimestamp().GetLSW() << ")" << std::endl;
+ std::cout << " RTP timestamp: " << SRinf.GetRTPTimestamp()
+ << " (" << SRprevinf.GetRTPTimestamp() << ")" << std::endl;
+ std::cout << " Packet count: " << SRinf.GetPacketCount()
+ << " (" << SRprevinf.GetPacketCount() << ")" << std::endl;
+ std::cout << " Octet count: " << SRinf.GetByteCount()
+ << " (" << SRprevinf.GetByteCount() <<")" << std::endl;
+ std::cout << " Receive time: " << SRinf.GetReceiveTime().GetSeconds()
+ << " (" << SRprevinf.GetReceiveTime().GetSeconds() << ")" << std::endl;
+ }
+ }
+ if (RRinf.HasInfo())
+ {
+ if (!RRprevinf.HasInfo())
+ {
+ std::cout << " RR Info:" << std::endl;
+ std::cout << " Fraction lost: " << RRinf.GetFractionLost() << std::endl;
+ std::cout << " Packets lost: " << RRinf.GetPacketsLost() << std::endl;
+ std::cout << " Ext.High.Seq: " << RRinf.GetExtendedHighestSequenceNumber() << std::endl;
+ std::cout << " Jitter: " << RRinf.GetJitter() << std::endl;
+ std::cout << " LSR: " << RRinf.GetLastSRTimestamp() << std::endl;
+ std::cout << " DLSR: " << RRinf.GetDelaySinceLastSR() << std::endl;
+ std::cout << " Receive time: " << RRinf.GetReceiveTime().GetSeconds() << std::endl;
+ }
+ else
+ {
+ std::cout << " RR Info:" << std::endl;
+ std::cout << " Fraction lost: " << RRinf.GetFractionLost()
+ << " (" << RRprevinf.GetFractionLost() << ")" << std::endl;
+ std::cout << " Packets lost: " << RRinf.GetPacketsLost()
+ << " (" << RRprevinf.GetPacketsLost() << ")" << std::endl;
+ std::cout << " Ext.High.Seq: " << RRinf.GetExtendedHighestSequenceNumber()
+ << " (" << RRprevinf.GetExtendedHighestSequenceNumber() << ")" << std::endl;
+ std::cout << " Jitter: " << RRinf.GetJitter()
+ << " (" << RRprevinf.GetJitter() << ")" << std::endl;
+ std::cout << " LSR: " << RRinf.GetLastSRTimestamp()
+ << " (" << RRprevinf.GetLastSRTimestamp() << ")" << std::endl;
+ std::cout << " DLSR: " << RRinf.GetDelaySinceLastSR()
+ << " (" << RRprevinf.GetDelaySinceLastSR() << ")" << std::endl;
+ std::cout << " Receive time: " << RRinf.GetReceiveTime().GetSeconds()
+ << " (" << RRprevinf.GetReceiveTime().GetSeconds() <<")" << std::endl;
+ }
+ }
+ std::cout << " Stats:" << std::endl;
+ std::cout << " Sent data: " << ((stats.HasSentData())?"Yes":"No") << std::endl;
+ std::cout << " Packets received: " << stats.GetNumPacketsReceived() << std::endl;
+ std::cout << " Seq. base: " << stats.GetBaseSequenceNumber() << std::endl;
+ std::cout << " Ext.High.Seq: " << stats.GetExtendedHighestSequenceNumber() << std::endl;
+ std::cout << " Jitter: " << stats.GetJitter() << std::endl;
+ std::cout << " New packets: " << stats.GetNumPacketsReceivedInInterval() << std::endl;
+ std::cout << " Saved seq. nr.: " << stats.GetSavedExtendedSequenceNumber() << std::endl;
+ std::cout << " RTT: " << INF_GetRoundtripTime().GetDouble() << " seconds" << std::endl;
+ if (INF_GetEstimatedTimestampUnit() > 0)
+ std::cout << " Estimated: " << (1.0/INF_GetEstimatedTimestampUnit()) << " samples per second" << std::endl;
+ std::cout << " SDES Info:" << std::endl;
+
+ size_t len;
+ char str[1024];
+ uint8_t *val;
+
+ if ((val = SDESinf.GetCNAME(&len)) != 0)
+ {
+ memcpy(str,val,len);
+ str[len] = 0;
+ std::cout << " CNAME: " << std::string(str) << std::endl;
+ }
+ if ((val = SDESinf.GetName(&len)) != 0)
+ {
+ memcpy(str,val,len);
+ str[len] = 0;
+ std::cout << " Name: " << std::string(str) << std::endl;
+ }
+ if ((val = SDESinf.GetEMail(&len)) != 0)
+ {
+ memcpy(str,val,len);
+ str[len] = 0;
+ std::cout << " EMail: " << std::string(str) << std::endl;
+ }
+ if ((val = SDESinf.GetPhone(&len)) != 0)
+ {
+ memcpy(str,val,len);
+ str[len] = 0;
+ std::cout << " phone: " << std::string(str) << std::endl;
+ }
+ if ((val = SDESinf.GetLocation(&len)) != 0)
+ {
+ memcpy(str,val,len);
+ str[len] = 0;
+ std::cout << " Location: " << std::string(str) << std::endl;
+ }
+ if ((val = SDESinf.GetTool(&len)) != 0)
+ {
+ memcpy(str,val,len);
+ str[len] = 0;
+ std::cout << " Tool: " << std::string(str) << std::endl;
+ }
+ if ((val = SDESinf.GetNote(&len)) != 0)
+ {
+ memcpy(str,val,len);
+ str[len] = 0;
+ std::cout << " Note: " << std::string(str) << std::endl;
+ }
+#ifdef RTP_SUPPORT_SDESPRIV
+ SDESinf.GotoFirstPrivateValue();
+ uint8_t *pref;
+ size_t preflen;
+ while (SDESinf.GetNextPrivateValue(&pref,&preflen,&val,&len))
+ {
+ char prefstr[1024];
+ memcpy(prefstr,pref,preflen);
+ memcpy(str,val,len);
+ prefstr[preflen] = 0;
+ str[len] = 0;
+ std::cout << " Private: " << std::string(prefstr) << ":" << std::string(str) << std::endl;
+ }
+#endif // RTP_SUPPORT_SDESPRIV
+ if (byereason)
+ {
+ memcpy(str,byereason,byereasonlen);
+ str[byereasonlen] = 0;
+ std::cout << " BYE Reason: " << std::string(str) << std::endl;
+ }
+}
+
+#endif // RTPDEBUG
+
diff --git a/src/rtpsourcedata.h b/src/rtpsourcedata.h
new file mode 100644
index 0000000..e2c925c
--- /dev/null
+++ b/src/rtpsourcedata.h
@@ -0,0 +1,474 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpsourcedata.h
+ */
+
+#ifndef RTPSOURCEDATA_H
+
+#define RTPSOURCEDATA_H
+
+#include "rtpconfig.h"
+#include "rtptimeutilities.h"
+#include "rtppacket.h"
+#include "rtcpsdesinfo.h"
+#include "rtptypes.h"
+#include "rtpsources.h"
+#include "rtpmemoryobject.h"
+#include <list>
+
+class RTPAddress;
+
+class RTCPSenderReportInfo
+{
+public:
+ RTCPSenderReportInfo():ntptimestamp(0,0),receivetime(0,0) { hasinfo = false; rtptimestamp = 0; packetcount = 0; bytecount = 0; }
+ void Set(const RTPNTPTime &ntptime,uint32_t rtptime,uint32_t pcount,
+ uint32_t bcount,const RTPTime &rcvtime) { ntptimestamp = ntptime; rtptimestamp = rtptime; packetcount = pcount; bytecount = bcount; receivetime = rcvtime; hasinfo = true; }
+
+ bool HasInfo() const { return hasinfo; }
+ RTPNTPTime GetNTPTimestamp() const { return ntptimestamp; }
+ uint32_t GetRTPTimestamp() const { return rtptimestamp; }
+ uint32_t GetPacketCount() const { return packetcount; }
+ uint32_t GetByteCount() const { return bytecount; }
+ RTPTime GetReceiveTime() const { return receivetime; }
+private:
+ bool hasinfo;
+ RTPNTPTime ntptimestamp;
+ uint32_t rtptimestamp;
+ uint32_t packetcount;
+ uint32_t bytecount;
+ RTPTime receivetime;
+};
+
+class RTCPReceiverReportInfo
+{
+public:
+ RTCPReceiverReportInfo():receivetime(0,0) { hasinfo = false; fractionlost = 0; packetslost = 0; exthighseqnr = 0; jitter = 0; lsr = 0; dlsr = 0; }
+ void Set(uint8_t fraclost,int32_t plost,uint32_t exthigh,
+ uint32_t jit,uint32_t l,uint32_t dl,const RTPTime &rcvtime) { fractionlost = ((double)fraclost)/256.0; packetslost = plost; exthighseqnr = exthigh; jitter = jit; lsr = l; dlsr = dl; receivetime = rcvtime; hasinfo = true; }
+
+ bool HasInfo() const { return hasinfo; }
+ double GetFractionLost() const { return fractionlost; }
+ int32_t GetPacketsLost() const { return packetslost; }
+ uint32_t GetExtendedHighestSequenceNumber() const { return exthighseqnr; }
+ uint32_t GetJitter() const { return jitter; }
+ uint32_t GetLastSRTimestamp() const { return lsr; }
+ uint32_t GetDelaySinceLastSR() const { return dlsr; }
+ RTPTime GetReceiveTime() const { return receivetime; }
+private:
+ bool hasinfo;
+ double fractionlost;
+ int32_t packetslost;
+ uint32_t exthighseqnr;
+ uint32_t jitter;
+ uint32_t lsr;
+ uint32_t dlsr;
+ RTPTime receivetime;
+};
+
+class RTPSourceStats
+{
+public:
+ RTPSourceStats();
+ void ProcessPacket(RTPPacket *pack,const RTPTime &receivetime,double tsunit,bool ownpacket,bool *accept,bool applyprobation,bool *onprobation);
+
+ bool HasSentData() const { return sentdata; }
+ uint32_t GetNumPacketsReceived() const { return packetsreceived; }
+ uint32_t GetBaseSequenceNumber() const { return baseseqnr; }
+ uint32_t GetExtendedHighestSequenceNumber() const { return exthighseqnr; }
+ uint32_t GetJitter() const { return jitter; }
+
+ int32_t GetNumPacketsReceivedInInterval() const { return numnewpackets; }
+ uint32_t GetSavedExtendedSequenceNumber() const { return savedextseqnr; }
+ void StartNewInterval() { numnewpackets = 0; savedextseqnr = exthighseqnr; }
+
+ void SetLastMessageTime(const RTPTime &t) { lastmsgtime = t; }
+ RTPTime GetLastMessageTime() const { return lastmsgtime; }
+ void SetLastRTPPacketTime(const RTPTime &t) { lastrtptime = t; }
+ RTPTime GetLastRTPPacketTime() const { return lastrtptime; }
+
+ void SetLastNoteTime(const RTPTime &t) { lastnotetime = t; }
+ RTPTime GetLastNoteTime() const { return lastnotetime; }
+private:
+ bool sentdata;
+ uint32_t packetsreceived;
+ uint32_t numcycles; // shifted left 16 bits
+ uint32_t baseseqnr;
+ uint32_t exthighseqnr,prevexthighseqnr;
+ uint32_t jitter,prevtimestamp;
+ double djitter;
+ RTPTime prevpacktime;
+ RTPTime lastmsgtime;
+ RTPTime lastrtptime;
+ RTPTime lastnotetime;
+ uint32_t numnewpackets;
+ uint32_t savedextseqnr;
+#ifdef RTP_SUPPORT_PROBATION
+ uint16_t prevseqnr;
+ int probation;
+ RTPSources::ProbationType probationtype;
+#endif // RTP_SUPPORT_PROBATION
+};
+
+inline RTPSourceStats::RTPSourceStats():prevpacktime(0,0),lastmsgtime(0,0),lastrtptime(0,0),lastnotetime(0,0)
+{
+ sentdata = false;
+ packetsreceived = 0;
+ baseseqnr = 0;
+ exthighseqnr = 0;
+ prevexthighseqnr = 0;
+ jitter = 0;
+ numcycles = 0;
+ numnewpackets = 0;
+ prevtimestamp = 0;
+ djitter = 0;
+ savedextseqnr = 0;
+#ifdef RTP_SUPPORT_PROBATION
+ probation = 0;
+ prevseqnr = 0;
+#endif // RTP_SUPPORT_PROBATION
+}
+
+/** Describes an entry in the RTPSources source table. */
+class RTPSourceData : public RTPMemoryObject
+{
+protected:
+ RTPSourceData(uint32_t ssrc, RTPMemoryManager *mgr = 0);
+ virtual ~RTPSourceData();
+public:
+ /** Extracts the first packet of this participants RTP packet queue. */
+ RTPPacket *GetNextPacket();
+
+ /** Clears the participant's RTP packet list. */
+ void FlushPackets();
+
+ /** Returns \c true if there are RTP packets which can be extracted. */
+ bool HasData() const { if (!validated) return false; return packetlist.empty()?false:true; }
+
+ /** Returns the SSRC identifier for this member. */
+ uint32_t GetSSRC() const { return ssrc; }
+
+ /** Returns \c true if the participant was added using the RTPSources member function CreateOwnSSRC and
+ * returns \c false otherwise.
+ */
+ bool IsOwnSSRC() const { return ownssrc; }
+
+ /** Returns \c true if the source identifier is actually a CSRC from an RTP packet. */
+ bool IsCSRC() const { return iscsrc; }
+
+ /** Returns \c true if this member is marked as a sender and \c false if not. */
+ bool IsSender() const { return issender; }
+
+ /** Returns \c true if the participant is validated, which is the case if a number of
+ * consecutive RTP packets have been received or if a CNAME item has been received for
+ * this participant.
+ */
+ bool IsValidated() const { return validated; }
+
+ /** Returns \c true if the source was validated and had not yet sent a BYE packet. */
+ bool IsActive() const { if (!validated) return false; if (receivedbye) return false; return true; }
+
+ /** This function is used by the RTCPPacketBuilder class to mark whether this participant's
+ * information has been processed in a report block or not.
+ */
+ void SetProcessedInRTCP(bool v) { processedinrtcp = v; }
+
+ /** This function is used by the RTCPPacketBuilder class and returns whether this participant
+ * has been processed in a report block or not.
+ */
+ bool IsProcessedInRTCP() const { return processedinrtcp; }
+
+ /** Returns \c true if the address from which this participant's RTP packets originate has
+ * already been set.
+ */
+ bool IsRTPAddressSet() const { return isrtpaddrset; }
+
+ /** Returns \c true if the address from which this participant's RTCP packets originate has
+ * already been set.
+ */
+ bool IsRTCPAddressSet() const { return isrtcpaddrset; }
+
+ /** Returns the address from which this participant's RTP packets originate.
+ * Returns the address from which this participant's RTP packets originate. If the address has
+ * been set and the returned value is NULL, this indicates that it originated from the local
+ * participant.
+ */
+ const RTPAddress *GetRTPDataAddress() const { return rtpaddr; }
+
+ /** Returns the address from which this participant's RTCP packets originate.
+ * Returns the address from which this participant's RTCP packets originate. If the address has
+ * been set and the returned value is NULL, this indicates that it originated from the local
+ * participant.
+ */
+ const RTPAddress *GetRTCPDataAddress() const { return rtcpaddr; }
+
+ /** Returns \c true if we received a BYE message for this participant and \c false otherwise. */
+ bool ReceivedBYE() const { return receivedbye; }
+
+ /** Returns the reason for leaving contained in the BYE packet of this participant.
+ * Returns the reason for leaving contained in the BYE packet of this participant. The length of
+ * the reason is stored in \c len.
+ */
+ uint8_t *GetBYEReason(size_t *len) const { *len = byereasonlen; return byereason; }
+
+ /** Returns the time at which the BYE packet was received. */
+ RTPTime GetBYETime() const { return byetime; }
+
+ /** Sets the value for the timestamp unit to be used in jitter calculations for data received from this participant.
+ * Sets the value for the timestamp unit to be used in jitter calculations for data received from this participant.
+ * If not set, the library uses an approximation for the timestamp unit which is calculated from two consecutive
+ * RTCP sender reports. The timestamp unit is defined as a time interval divided by the corresponding timestamp
+ * interval. For 8000 Hz audio this would be 1/8000. For video, often a timestamp unit of 1/90000 is used.
+ */
+ void SetTimestampUnit(double tsu) { timestampunit = tsu; }
+
+ /** Returns the timestamp unit used for this participant. */
+ double GetTimestampUnit() const { return timestampunit; }
+
+ /** Returns \c true if an RTCP sender report has been received from this participant. */
+ bool SR_HasInfo() const { return SRinf.HasInfo(); }
+
+ /** Returns the NTP timestamp contained in the last sender report. */
+ RTPNTPTime SR_GetNTPTimestamp() const { return SRinf.GetNTPTimestamp(); }
+
+ /** Returns the RTP timestamp contained in the last sender report. */
+ uint32_t SR_GetRTPTimestamp() const { return SRinf.GetRTPTimestamp(); }
+
+ /** Returns the packet count contained in the last sender report. */
+ uint32_t SR_GetPacketCount() const { return SRinf.GetPacketCount(); }
+
+ /** Returns the octet count contained in the last sender report. */
+ uint32_t SR_GetByteCount() const { return SRinf.GetByteCount(); }
+
+ /** Returns the time at which the last sender report was received. */
+ RTPTime SR_GetReceiveTime() const { return SRinf.GetReceiveTime(); }
+
+ /** Returns \c true if more than one RTCP sender report has been received. */
+ bool SR_Prev_HasInfo() const { return SRprevinf.HasInfo(); }
+
+ /** Returns the NTP timestamp contained in the second to last sender report. */
+ RTPNTPTime SR_Prev_GetNTPTimestamp() const { return SRprevinf.GetNTPTimestamp(); }
+
+ /** Returns the RTP timestamp contained in the second to last sender report. */
+ uint32_t SR_Prev_GetRTPTimestamp() const { return SRprevinf.GetRTPTimestamp(); }
+
+ /** Returns the packet count contained in the second to last sender report. */
+ uint32_t SR_Prev_GetPacketCount() const { return SRprevinf.GetPacketCount(); }
+
+ /** Returns the octet count contained in the second to last sender report. */
+ uint32_t SR_Prev_GetByteCount() const { return SRprevinf.GetByteCount(); }
+
+ /** Returns the time at which the second to last sender report was received. */
+ RTPTime SR_Prev_GetReceiveTime() const { return SRprevinf.GetReceiveTime(); }
+
+ /** Returns \c true if this participant sent a receiver report with information about the reception of our data. */
+ bool RR_HasInfo() const { return RRinf.HasInfo(); }
+
+ /** Returns the fraction lost value from the last report. */
+ double RR_GetFractionLost() const { return RRinf.GetFractionLost(); }
+
+ /** Returns the number of lost packets contained in the last report. */
+ int32_t RR_GetPacketsLost() const { return RRinf.GetPacketsLost(); }
+
+ /** Returns the extended highest sequence number contained in the last report. */
+ uint32_t RR_GetExtendedHighestSequenceNumber() const { return RRinf.GetExtendedHighestSequenceNumber(); }
+
+ /** Returns the jitter value from the last report. */
+ uint32_t RR_GetJitter() const { return RRinf.GetJitter(); }
+
+ /** Returns the LSR value from the last report. */
+ uint32_t RR_GetLastSRTimestamp() const { return RRinf.GetLastSRTimestamp(); }
+
+ /** Returns the DLSR value from the last report. */
+ uint32_t RR_GetDelaySinceLastSR() const { return RRinf.GetDelaySinceLastSR(); }
+
+ /** Returns the time at which the last report was received. */
+ RTPTime RR_GetReceiveTime() const { return RRinf.GetReceiveTime(); }
+
+ /** Returns \c true if this participant sent more than one receiver report with information
+ * about the reception of our data.
+ */
+ bool RR_Prev_HasInfo() const { return RRprevinf.HasInfo(); }
+
+ /** Returns the fraction lost value from the second to last report. */
+ double RR_Prev_GetFractionLost() const { return RRprevinf.GetFractionLost(); }
+
+ /** Returns the number of lost packets contained in the second to last report. */
+ int32_t RR_Prev_GetPacketsLost() const { return RRprevinf.GetPacketsLost(); }
+
+ /** Returns the extended highest sequence number contained in the second to last report. */
+ uint32_t RR_Prev_GetExtendedHighestSequenceNumber() const { return RRprevinf.GetExtendedHighestSequenceNumber(); }
+
+ /** Returns the jitter value from the second to last report. */
+ uint32_t RR_Prev_GetJitter() const { return RRprevinf.GetJitter(); }
+
+ /** Returns the LSR value from the second to last report. */
+ uint32_t RR_Prev_GetLastSRTimestamp() const { return RRprevinf.GetLastSRTimestamp(); }
+
+ /** Returns the DLSR value from the second to last report. */
+ uint32_t RR_Prev_GetDelaySinceLastSR() const { return RRprevinf.GetDelaySinceLastSR(); }
+
+ /** Returns the time at which the second to last report was received. */
+ RTPTime RR_Prev_GetReceiveTime() const { return RRprevinf.GetReceiveTime(); }
+
+ /** Returns \c true if validated RTP packets have been received from this participant. */
+ bool INF_HasSentData() const { return stats.HasSentData(); }
+
+ /** Returns the total number of received packets from this participant. */
+ int32_t INF_GetNumPacketsReceived() const { return stats.GetNumPacketsReceived(); }
+
+ /** Returns the base sequence number of this participant. */
+ uint32_t INF_GetBaseSequenceNumber() const { return stats.GetBaseSequenceNumber(); }
+
+ /** Returns the extended highest sequence number received from this participant. */
+ uint32_t INF_GetExtendedHighestSequenceNumber() const { return stats.GetExtendedHighestSequenceNumber(); }
+
+ /** Returns the current jitter value for this participant. */
+ uint32_t INF_GetJitter() const { return stats.GetJitter(); }
+
+ /** Returns the time at which something was last heard from this member. */
+ RTPTime INF_GetLastMessageTime() const { return stats.GetLastMessageTime(); }
+
+ /** Returns the time at which the last RTP packet was received. */
+ RTPTime INF_GetLastRTPPacketTime() const { return stats.GetLastRTPPacketTime(); }
+
+ /** Returns the estimated timestamp unit, calculated from two consecutive sender reports. */
+ double INF_GetEstimatedTimestampUnit() const;
+
+ /** Returns the number of packets received since a new interval was started with INF_StartNewInterval. */
+ uint32_t INF_GetNumPacketsReceivedInInterval() const { return stats.GetNumPacketsReceivedInInterval(); }
+
+ /** Returns the extended sequence number which was stored by the INF_StartNewInterval call. */
+ uint32_t INF_GetSavedExtendedSequenceNumber() const { return stats.GetSavedExtendedSequenceNumber(); }
+
+ /** Starts a new interval to count received packets in; this also stores the current extended highest sequence
+ * number to be able to calculate the packet loss during the interval.
+ */
+ void INF_StartNewInterval() { stats.StartNewInterval(); }
+
+ /** Estimates the round trip time by using the LSR and DLSR info from the last receiver report. */
+ RTPTime INF_GetRoundtripTime() const;
+
+ /** Returns the time at which the last SDES NOTE item was received. */
+ RTPTime INF_GetLastSDESNoteTime() const { return stats.GetLastNoteTime(); }
+
+ /** Returns a pointer to the SDES CNAME item of this participant and stores its length in \c len. */
+ uint8_t *SDES_GetCNAME(size_t *len) const { return SDESinf.GetCNAME(len); }
+
+ /** Returns a pointer to the SDES name item of this participant and stores its length in \c len. */
+ uint8_t *SDES_GetName(size_t *len) const { return SDESinf.GetName(len); }
+
+ /** Returns a pointer to the SDES e-mail item of this participant and stores its length in \c len. */
+ uint8_t *SDES_GetEMail(size_t *len) const { return SDESinf.GetEMail(len); }
+
+ /** Returns a pointer to the SDES phone item of this participant and stores its length in \c len. */
+ uint8_t *SDES_GetPhone(size_t *len) const { return SDESinf.GetPhone(len); }
+
+ /** Returns a pointer to the SDES location item of this participant and stores its length in \c len. */
+ uint8_t *SDES_GetLocation(size_t *len) const { return SDESinf.GetLocation(len); }
+
+ /** Returns a pointer to the SDES tool item of this participant and stores its length in \c len. */
+ uint8_t *SDES_GetTool(size_t *len) const { return SDESinf.GetTool(len); }
+
+ /** Returns a pointer to the SDES note item of this participant and stores its length in \c len. */
+ uint8_t *SDES_GetNote(size_t *len) const { return SDESinf.GetNote(len); }
+
+#ifdef RTP_SUPPORT_SDESPRIV
+ /** Starts the iteration over the stored SDES private item prefixes and their associated values. */
+ void SDES_GotoFirstPrivateValue() { SDESinf.GotoFirstPrivateValue(); }
+
+ /** If available, returns \c true and stores the next SDES private item prefix in \c prefix and its length in
+ * \c prefixlen; the associated value and its length are then stored in \c value and \c valuelen.
+ */
+ bool SDES_GetNextPrivateValue(uint8_t **prefix,size_t *prefixlen,uint8_t **value,size_t *valuelen) { return SDESinf.GetNextPrivateValue(prefix,prefixlen,value,valuelen); }
+
+ /** Looks for the entry which corresponds to the SDES private item prefix \c prefix with length
+ * \c prefixlen; if found, the function returns \c true and stores the associated value and
+ * its length in \c value and \c valuelen respectively.
+ */
+ bool SDES_GetPrivateValue(uint8_t *prefix,size_t prefixlen,uint8_t **value,size_t *valuelen) const { return SDESinf.GetPrivateValue(prefix,prefixlen,value,valuelen); }
+#endif // RTP_SUPPORT_SDESPRIV
+
+#ifdef RTPDEBUG
+ virtual void Dump();
+#endif // RTPDEBUG
+protected:
+ std::list<RTPPacket *> packetlist;
+
+ uint32_t ssrc;
+ bool ownssrc;
+ bool iscsrc;
+ double timestampunit;
+ bool receivedbye;
+ bool validated;
+ bool processedinrtcp;
+ bool issender;
+
+ RTCPSenderReportInfo SRinf,SRprevinf;
+ RTCPReceiverReportInfo RRinf,RRprevinf;
+ RTPSourceStats stats;
+ RTCPSDESInfo SDESinf;
+
+ bool isrtpaddrset,isrtcpaddrset;
+ RTPAddress *rtpaddr,*rtcpaddr;
+
+ RTPTime byetime;
+ uint8_t *byereason;
+ size_t byereasonlen;
+};
+
+inline RTPPacket *RTPSourceData::GetNextPacket()
+{
+ if (!validated)
+ return 0;
+
+ RTPPacket *p;
+
+ if (packetlist.empty())
+ return 0;
+ p = *(packetlist.begin());
+ packetlist.pop_front();
+ return p;
+}
+
+inline void RTPSourceData::FlushPackets()
+{
+ std::list<RTPPacket *>::const_iterator it;
+
+ for (it = packetlist.begin() ; it != packetlist.end() ; ++it)
+ RTPDelete(*it,GetMemoryManager());
+ packetlist.clear();
+}
+#endif // RTPSOURCEDATA_H
+
diff --git a/src/rtpsources.cpp b/src/rtpsources.cpp
new file mode 100644
index 0000000..7318bc6
--- /dev/null
+++ b/src/rtpsources.cpp
@@ -0,0 +1,1412 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtpsources.h"
+#include "rtperrors.h"
+#include "rtprawpacket.h"
+#include "rtpinternalsourcedata.h"
+#include "rtptimeutilities.h"
+#include "rtpdefines.h"
+#include "rtcpcompoundpacket.h"
+#include "rtcppacket.h"
+#include "rtcpapppacket.h"
+#include "rtcpbyepacket.h"
+#include "rtcpsdespacket.h"
+#include "rtcpsrpacket.h"
+#include "rtcprrpacket.h"
+#include "rtptransmitter.h"
+
+#ifdef RTPDEBUG
+ #include <iostream>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+RTPSources::RTPSources(ProbationType probtype,RTPMemoryManager *mgr) : RTPMemoryObject(mgr),sourcelist(mgr,RTPMEM_TYPE_CLASS_SOURCETABLEHASHELEMENT)
+{
+ totalcount = 0;
+ sendercount = 0;
+ activecount = 0;
+ owndata = 0;
+#ifdef RTP_SUPPORT_PROBATION
+ probationtype = probtype;
+#endif // RTP_SUPPORT_PROBATION
+}
+
+RTPSources::~RTPSources()
+{
+ Clear();
+}
+
+void RTPSources::Clear()
+{
+ ClearSourceList();
+}
+
+void RTPSources::ClearSourceList()
+{
+ sourcelist.GotoFirstElement();
+ while (sourcelist.HasCurrentElement())
+ {
+ RTPInternalSourceData *sourcedata;
+
+ sourcedata = sourcelist.GetCurrentElement();
+ RTPDelete(sourcedata,GetMemoryManager());
+ sourcelist.GotoNextElement();
+ }
+ sourcelist.Clear();
+ owndata = 0;
+ totalcount = 0;
+ sendercount = 0;
+ activecount = 0;
+}
+
+int RTPSources::CreateOwnSSRC(uint32_t ssrc)
+{
+ if (owndata != 0)
+ return ERR_RTP_SOURCES_ALREADYHAVEOWNSSRC;
+ if (GotEntry(ssrc))
+ return ERR_RTP_SOURCES_SSRCEXISTS;
+
+ int status;
+ bool created;
+
+ status = ObtainSourceDataInstance(ssrc,&owndata,&created);
+ if (status < 0)
+ {
+ owndata = 0; // just to make sure
+ return status;
+ }
+ owndata->SetOwnSSRC();
+ owndata->SetRTPDataAddress(0);
+ owndata->SetRTCPDataAddress(0);
+
+ // we've created a validated ssrc, so we should increase activecount
+ activecount++;
+
+ OnNewSource(owndata);
+ return 0;
+}
+
+int RTPSources::DeleteOwnSSRC()
+{
+ if (owndata == 0)
+ return ERR_RTP_SOURCES_DONTHAVEOWNSSRC;
+
+ uint32_t ssrc = owndata->GetSSRC();
+
+ sourcelist.GotoElement(ssrc);
+ sourcelist.DeleteCurrentElement();
+
+ totalcount--;
+ if (owndata->IsSender())
+ sendercount--;
+ if (owndata->IsActive())
+ activecount--;
+
+ OnRemoveSource(owndata);
+
+ RTPDelete(owndata,GetMemoryManager());
+ owndata = 0;
+ return 0;
+}
+
+void RTPSources::SentRTPPacket()
+{
+ if (owndata == 0)
+ return;
+
+ bool prevsender = owndata->IsSender();
+
+ owndata->SentRTPPacket();
+ if (!prevsender && owndata->IsSender())
+ sendercount++;
+}
+
+int RTPSources::ProcessRawPacket(RTPRawPacket *rawpack,RTPTransmitter *rtptrans,bool acceptownpackets)
+{
+ RTPTransmitter *transmitters[1];
+ int num;
+
+ transmitters[0] = rtptrans;
+ if (rtptrans == 0)
+ num = 0;
+ else
+ num = 1;
+ return ProcessRawPacket(rawpack,transmitters,num,acceptownpackets);
+}
+
+int RTPSources::ProcessRawPacket(RTPRawPacket *rawpack,RTPTransmitter *rtptrans[],int numtrans,bool acceptownpackets)
+{
+ int status;
+
+ if (rawpack->IsRTP()) // RTP packet
+ {
+ RTPPacket *rtppack;
+
+ // First, we'll see if the packet can be parsed
+ rtppack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPPACKET) RTPPacket(*rawpack,GetMemoryManager());
+ if (rtppack == 0)
+ return ERR_RTP_OUTOFMEM;
+ if ((status = rtppack->GetCreationError()) < 0)
+ {
+ if (status == ERR_RTP_PACKET_INVALIDPACKET)
+ {
+ RTPDelete(rtppack,GetMemoryManager());
+ rtppack = 0;
+ }
+ else
+ {
+ RTPDelete(rtppack,GetMemoryManager());
+ return status;
+ }
+ }
+
+ // Check if the packet was valid
+ if (rtppack != 0)
+ {
+ bool stored = false;
+ bool ownpacket = false;
+ int i;
+ const RTPAddress *senderaddress = rawpack->GetSenderAddress();
+
+ for (i = 0 ; !ownpacket && i < numtrans ; i++)
+ {
+ if (rtptrans[i]->ComesFromThisTransmitter(senderaddress))
+ ownpacket = true;
+ }
+
+ // Check if the packet is our own.
+ if (ownpacket)
+ {
+ // Now it depends on the user's preference
+ // what to do with this packet:
+ if (acceptownpackets)
+ {
+ // sender addres for own packets has to be NULL!
+ if ((status = ProcessRTPPacket(rtppack,rawpack->GetReceiveTime(),0,&stored)) < 0)
+ {
+ if (!stored)
+ RTPDelete(rtppack,GetMemoryManager());
+ return status;
+ }
+ }
+ }
+ else
+ {
+ if ((status = ProcessRTPPacket(rtppack,rawpack->GetReceiveTime(),senderaddress,&stored)) < 0)
+ {
+ if (!stored)
+ RTPDelete(rtppack,GetMemoryManager());
+ return status;
+ }
+ }
+ if (!stored)
+ RTPDelete(rtppack,GetMemoryManager());
+ }
+ }
+ else // RTCP packet
+ {
+ RTCPCompoundPacket rtcpcomppack(*rawpack,GetMemoryManager());
+ bool valid = false;
+
+ if ((status = rtcpcomppack.GetCreationError()) < 0)
+ {
+ if (status != ERR_RTP_RTCPCOMPOUND_INVALIDPACKET)
+ return status;
+ }
+ else
+ valid = true;
+
+
+ if (valid)
+ {
+ bool ownpacket = false;
+ int i;
+ const RTPAddress *senderaddress = rawpack->GetSenderAddress();
+
+ for (i = 0 ; !ownpacket && i < numtrans ; i++)
+ {
+ if (rtptrans[i]->ComesFromThisTransmitter(senderaddress))
+ ownpacket = true;
+ }
+
+ // First check if it's a packet of this session.
+ if (ownpacket)
+ {
+ if (acceptownpackets)
+ {
+ // sender address for own packets has to be NULL
+ status = ProcessRTCPCompoundPacket(&rtcpcomppack,rawpack->GetReceiveTime(),0);
+ if (status < 0)
+ return status;
+ }
+ }
+ else // not our own packet
+ {
+ status = ProcessRTCPCompoundPacket(&rtcpcomppack,rawpack->GetReceiveTime(),rawpack->GetSenderAddress());
+ if (status < 0)
+ return status;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int RTPSources::ProcessRTPPacket(RTPPacket *rtppack,const RTPTime &receivetime,const RTPAddress *senderaddress,bool *stored)
+{
+ uint32_t ssrc;
+ RTPInternalSourceData *srcdat;
+ int status;
+ bool created;
+
+ OnRTPPacket(rtppack,receivetime,senderaddress);
+
+ *stored = false;
+
+ ssrc = rtppack->GetSSRC();
+ if ((status = ObtainSourceDataInstance(ssrc,&srcdat,&created)) < 0)
+ return status;
+
+ if (created)
+ {
+ if ((status = srcdat->SetRTPDataAddress(senderaddress)) < 0)
+ return status;
+ }
+ else // got a previously existing source
+ {
+ if (CheckCollision(srcdat,senderaddress,true))
+ return 0; // ignore packet on collision
+ }
+
+ bool prevsender = srcdat->IsSender();
+ bool prevactive = srcdat->IsActive();
+
+ // The packet comes from a valid source, we can process it further now
+ // The following function should delete rtppack itself if something goes
+ // wrong
+ if ((status = srcdat->ProcessRTPPacket(rtppack,receivetime,stored)) < 0)
+ return status;
+
+ if (!prevsender && srcdat->IsSender())
+ sendercount++;
+ if (!prevactive && srcdat->IsActive())
+ activecount++;
+
+ if (created)
+ OnNewSource(srcdat);
+
+ if (srcdat->IsValidated()) // process the CSRCs
+ {
+ RTPInternalSourceData *csrcdat;
+ bool createdcsrc;
+
+ int num = rtppack->GetCSRCCount();
+ int i;
+
+ for (i = 0 ; i < num ; i++)
+ {
+ if ((status = ObtainSourceDataInstance(rtppack->GetCSRC(i),&csrcdat,&createdcsrc)) < 0)
+ return status;
+ if (createdcsrc)
+ {
+ csrcdat->SetCSRC();
+ if (csrcdat->IsActive())
+ activecount++;
+ OnNewSource(csrcdat);
+ }
+ else // already found an entry, possibly because of RTCP data
+ {
+ if (!CheckCollision(csrcdat,senderaddress,true))
+ csrcdat->SetCSRC();
+ }
+ }
+ }
+
+ return 0;
+}
+
+int RTPSources::ProcessRTCPCompoundPacket(RTCPCompoundPacket *rtcpcomppack,const RTPTime &receivetime,const RTPAddress *senderaddress)
+{
+ RTCPPacket *rtcppack;
+ int status;
+ bool gotownssrc = ((owndata == 0)?false:true);
+ uint32_t ownssrc = ((owndata != 0)?owndata->GetSSRC():0);
+
+ OnRTCPCompoundPacket(rtcpcomppack,receivetime,senderaddress);
+
+ rtcpcomppack->GotoFirstPacket();
+ while ((rtcppack = rtcpcomppack->GetNextPacket()) != 0)
+ {
+ if (rtcppack->IsKnownFormat())
+ {
+ switch (rtcppack->GetPacketType())
+ {
+ case RTCPPacket::SR:
+ {
+ RTCPSRPacket *p = (RTCPSRPacket *)rtcppack;
+ uint32_t senderssrc = p->GetSenderSSRC();
+
+ status = ProcessRTCPSenderInfo(senderssrc,p->GetNTPTimestamp(),p->GetRTPTimestamp(),
+ p->GetSenderPacketCount(),p->GetSenderOctetCount(),
+ receivetime,senderaddress);
+ if (status < 0)
+ return status;
+
+ bool gotinfo = false;
+ if (gotownssrc)
+ {
+ int i;
+ int num = p->GetReceptionReportCount();
+ for (i = 0 ; i < num ; i++)
+ {
+ if (p->GetSSRC(i) == ownssrc) // data is meant for us
+ {
+ gotinfo = true;
+ status = ProcessRTCPReportBlock(senderssrc,p->GetFractionLost(i),p->GetLostPacketCount(i),
+ p->GetExtendedHighestSequenceNumber(i),p->GetJitter(i),p->GetLSR(i),
+ p->GetDLSR(i),receivetime,senderaddress);
+ if (status < 0)
+ return status;
+ }
+ }
+ }
+ if (!gotinfo)
+ {
+ status = UpdateReceiveTime(senderssrc,receivetime,senderaddress);
+ if (status < 0)
+ return status;
+ }
+ }
+ break;
+ case RTCPPacket::RR:
+ {
+ RTCPRRPacket *p = (RTCPRRPacket *)rtcppack;
+ uint32_t senderssrc = p->GetSenderSSRC();
+
+ bool gotinfo = false;
+
+ if (gotownssrc)
+ {
+ int i;
+ int num = p->GetReceptionReportCount();
+ for (i = 0 ; i < num ; i++)
+ {
+ if (p->GetSSRC(i) == ownssrc)
+ {
+ gotinfo = true;
+ status = ProcessRTCPReportBlock(senderssrc,p->GetFractionLost(i),p->GetLostPacketCount(i),
+ p->GetExtendedHighestSequenceNumber(i),p->GetJitter(i),p->GetLSR(i),
+ p->GetDLSR(i),receivetime,senderaddress);
+ if (status < 0)
+ return status;
+ }
+ }
+ }
+ if (!gotinfo)
+ {
+ status = UpdateReceiveTime(senderssrc,receivetime,senderaddress);
+ if (status < 0)
+ return status;
+ }
+ }
+ break;
+ case RTCPPacket::SDES:
+ {
+ RTCPSDESPacket *p = (RTCPSDESPacket *)rtcppack;
+
+ if (p->GotoFirstChunk())
+ {
+ do
+ {
+ uint32_t sdesssrc = p->GetChunkSSRC();
+ bool updated = false;
+ if (p->GotoFirstItem())
+ {
+ do
+ {
+ RTCPSDESPacket::ItemType t;
+
+ if ((t = p->GetItemType()) != RTCPSDESPacket::PRIV)
+ {
+ updated = true;
+ status = ProcessSDESNormalItem(sdesssrc,t,p->GetItemLength(),p->GetItemData(),receivetime,senderaddress);
+ if (status < 0)
+ return status;
+ }
+#ifdef RTP_SUPPORT_SDESPRIV
+ else
+ {
+ updated = true;
+ status = ProcessSDESPrivateItem(sdesssrc,p->GetPRIVPrefixLength(),p->GetPRIVPrefixData(),p->GetPRIVValueLength(),
+ p->GetPRIVValueData(),receivetime,senderaddress);
+ if (status < 0)
+ return status;
+ }
+#endif // RTP_SUPPORT_SDESPRIV
+ } while (p->GotoNextItem());
+ }
+ if (!updated)
+ {
+ status = UpdateReceiveTime(sdesssrc,receivetime,senderaddress);
+ if (status < 0)
+ return status;
+ }
+ } while (p->GotoNextChunk());
+ }
+ }
+ break;
+ case RTCPPacket::BYE:
+ {
+ RTCPBYEPacket *p = (RTCPBYEPacket *)rtcppack;
+ int i;
+ int num = p->GetSSRCCount();
+
+ for (i = 0 ; i < num ; i++)
+ {
+ uint32_t byessrc = p->GetSSRC(i);
+ status = ProcessBYE(byessrc,p->GetReasonLength(),p->GetReasonData(),receivetime,senderaddress);
+ if (status < 0)
+ return status;
+ }
+ }
+ break;
+ case RTCPPacket::APP:
+ {
+ RTCPAPPPacket *p = (RTCPAPPPacket *)rtcppack;
+
+ OnAPPPacket(p,receivetime,senderaddress);
+ }
+ break;
+ case RTCPPacket::Unknown:
+ default:
+ {
+ OnUnknownPacketType(rtcppack,receivetime,senderaddress);
+ }
+ break;
+ }
+ }
+ else
+ {
+ OnUnknownPacketFormat(rtcppack,receivetime,senderaddress);
+ }
+ }
+
+ return 0;
+}
+
+bool RTPSources::GotoFirstSource()
+{
+ sourcelist.GotoFirstElement();
+ if (sourcelist.HasCurrentElement())
+ return true;
+ return false;
+}
+
+bool RTPSources::GotoNextSource()
+{
+ sourcelist.GotoNextElement();
+ if (sourcelist.HasCurrentElement())
+ return true;
+ return false;
+}
+
+bool RTPSources::GotoPreviousSource()
+{
+ sourcelist.GotoPreviousElement();
+ if (sourcelist.HasCurrentElement())
+ return true;
+ return false;
+}
+
+bool RTPSources::GotoFirstSourceWithData()
+{
+ bool found = false;
+
+ sourcelist.GotoFirstElement();
+ while (!found && sourcelist.HasCurrentElement())
+ {
+ RTPInternalSourceData *srcdat;
+
+ srcdat = sourcelist.GetCurrentElement();
+ if (srcdat->HasData())
+ found = true;
+ else
+ sourcelist.GotoNextElement();
+ }
+
+ return found;
+}
+
+bool RTPSources::GotoNextSourceWithData()
+{
+ bool found = false;
+
+ sourcelist.GotoNextElement();
+ while (!found && sourcelist.HasCurrentElement())
+ {
+ RTPInternalSourceData *srcdat;
+
+ srcdat = sourcelist.GetCurrentElement();
+ if (srcdat->HasData())
+ found = true;
+ else
+ sourcelist.GotoNextElement();
+ }
+
+ return found;
+}
+
+bool RTPSources::GotoPreviousSourceWithData()
+{
+ bool found = false;
+
+ sourcelist.GotoPreviousElement();
+ while (!found && sourcelist.HasCurrentElement())
+ {
+ RTPInternalSourceData *srcdat;
+
+ srcdat = sourcelist.GetCurrentElement();
+ if (srcdat->HasData())
+ found = true;
+ else
+ sourcelist.GotoNextElement();
+ }
+
+ return found;
+}
+
+RTPSourceData *RTPSources::GetCurrentSourceInfo()
+{
+ if (!sourcelist.HasCurrentElement())
+ return 0;
+ return sourcelist.GetCurrentElement();
+}
+
+RTPSourceData *RTPSources::GetSourceInfo(uint32_t ssrc)
+{
+ if (sourcelist.GotoElement(ssrc) < 0)
+ return 0;
+ if (!sourcelist.HasCurrentElement())
+ return 0;
+ return sourcelist.GetCurrentElement();
+}
+
+bool RTPSources::GotEntry(uint32_t ssrc)
+{
+ return sourcelist.HasElement(ssrc);
+}
+
+RTPPacket *RTPSources::GetNextPacket()
+{
+ if (!sourcelist.HasCurrentElement())
+ return 0;
+
+ RTPInternalSourceData *srcdat = sourcelist.GetCurrentElement();
+ RTPPacket *pack = srcdat->GetNextPacket();
+ return pack;
+}
+
+int RTPSources::ProcessRTCPSenderInfo(uint32_t ssrc,const RTPNTPTime &ntptime,uint32_t rtptime,
+ uint32_t packetcount,uint32_t octetcount,const RTPTime &receivetime,
+ const RTPAddress *senderaddress)
+{
+ RTPInternalSourceData *srcdat;
+ bool created;
+ int status;
+
+ status = GetRTCPSourceData(ssrc,senderaddress,&srcdat,&created);
+ if (status < 0)
+ return status;
+ if (srcdat == 0)
+ return 0;
+
+ srcdat->ProcessSenderInfo(ntptime,rtptime,packetcount,octetcount,receivetime);
+
+ // Call the callback
+ if (created)
+ OnNewSource(srcdat);
+
+ return 0;
+}
+
+int RTPSources::ProcessRTCPReportBlock(uint32_t ssrc,uint8_t fractionlost,int32_t lostpackets,
+ uint32_t exthighseqnr,uint32_t jitter,uint32_t lsr,
+ uint32_t dlsr,const RTPTime &receivetime,const RTPAddress *senderaddress)
+{
+ RTPInternalSourceData *srcdat;
+ bool created;
+ int status;
+
+ status = GetRTCPSourceData(ssrc,senderaddress,&srcdat,&created);
+ if (status < 0)
+ return status;
+ if (srcdat == 0)
+ return 0;
+
+ srcdat->ProcessReportBlock(fractionlost,lostpackets,exthighseqnr,jitter,lsr,dlsr,receivetime);
+
+ // Call the callback
+ if (created)
+ OnNewSource(srcdat);
+
+ return 0;
+}
+
+int RTPSources::ProcessSDESNormalItem(uint32_t ssrc,RTCPSDESPacket::ItemType t,size_t itemlength,
+ const void *itemdata,const RTPTime &receivetime,const RTPAddress *senderaddress)
+{
+ RTPInternalSourceData *srcdat;
+ bool created,cnamecollis;
+ int status;
+ uint8_t sdesid;
+ bool prevactive;
+
+ switch(t)
+ {
+ case RTCPSDESPacket::CNAME:
+ sdesid = RTCP_SDES_ID_CNAME;
+ break;
+ case RTCPSDESPacket::NAME:
+ sdesid = RTCP_SDES_ID_NAME;
+ break;
+ case RTCPSDESPacket::EMAIL:
+ sdesid = RTCP_SDES_ID_EMAIL;
+ break;
+ case RTCPSDESPacket::PHONE:
+ sdesid = RTCP_SDES_ID_PHONE;
+ break;
+ case RTCPSDESPacket::LOC:
+ sdesid = RTCP_SDES_ID_LOCATION;
+ break;
+ case RTCPSDESPacket::TOOL:
+ sdesid = RTCP_SDES_ID_TOOL;
+ break;
+ case RTCPSDESPacket::NOTE:
+ sdesid = RTCP_SDES_ID_NOTE;
+ break;
+ default:
+ return ERR_RTP_SOURCES_ILLEGALSDESTYPE;
+ }
+
+ status = GetRTCPSourceData(ssrc,senderaddress,&srcdat,&created);
+ if (status < 0)
+ return status;
+ if (srcdat == 0)
+ return 0;
+
+ prevactive = srcdat->IsActive();
+ status = srcdat->ProcessSDESItem(sdesid,(const uint8_t *)itemdata,itemlength,receivetime,&cnamecollis);
+ if (!prevactive && srcdat->IsActive())
+ activecount++;
+
+ // Call the callback
+ if (created)
+ OnNewSource(srcdat);
+ if (cnamecollis)
+ OnCNAMECollision(srcdat,senderaddress,(const uint8_t *)itemdata,itemlength);
+
+ return status;
+}
+
+#ifdef RTP_SUPPORT_SDESPRIV
+int RTPSources::ProcessSDESPrivateItem(uint32_t ssrc,size_t prefixlen,const void *prefixdata,
+ size_t valuelen,const void *valuedata,const RTPTime &receivetime,
+ const RTPAddress *senderaddress)
+{
+ RTPInternalSourceData *srcdat;
+ bool created;
+ int status;
+
+ status = GetRTCPSourceData(ssrc,senderaddress,&srcdat,&created);
+ if (status < 0)
+ return status;
+ if (srcdat == 0)
+ return 0;
+
+ status = srcdat->ProcessPrivateSDESItem((const uint8_t *)prefixdata,prefixlen,(const uint8_t *)valuedata,valuelen,receivetime);
+ // Call the callback
+ if (created)
+ OnNewSource(srcdat);
+ return status;
+}
+#endif //RTP_SUPPORT_SDESPRIV
+
+int RTPSources::ProcessBYE(uint32_t ssrc,size_t reasonlength,const void *reasondata,
+ const RTPTime &receivetime,const RTPAddress *senderaddress)
+{
+ RTPInternalSourceData *srcdat;
+ bool created;
+ int status;
+ bool prevactive;
+
+ status = GetRTCPSourceData(ssrc,senderaddress,&srcdat,&created);
+ if (status < 0)
+ return status;
+ if (srcdat == 0)
+ return 0;
+
+ // we'll ignore BYE packets for our own ssrc
+ if (srcdat == owndata)
+ return 0;
+
+ prevactive = srcdat->IsActive();
+ srcdat->ProcessBYEPacket((const uint8_t *)reasondata,reasonlength,receivetime);
+ if (prevactive && !srcdat->IsActive())
+ activecount--;
+
+ // Call the callback
+ if (created)
+ OnNewSource(srcdat);
+ OnBYEPacket(srcdat);
+ return 0;
+}
+
+int RTPSources::ObtainSourceDataInstance(uint32_t ssrc,RTPInternalSourceData **srcdat,bool *created)
+{
+ RTPInternalSourceData *srcdat2;
+ int status;
+
+ if (sourcelist.GotoElement(ssrc) < 0) // No entry for this source
+ {
+#ifdef RTP_SUPPORT_PROBATION
+ srcdat2 = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPINTERNALSOURCEDATA) RTPInternalSourceData(ssrc,probationtype,GetMemoryManager());
+#else
+ srcdat2 = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPINTERNALSOURCEDATA) RTPInternalSourceData(ssrc,RTPSources::NoProbation,GetMemoryManager());
+#endif // RTP_SUPPORT_PROBATION
+ if (srcdat2 == 0)
+ return ERR_RTP_OUTOFMEM;
+ if ((status = sourcelist.AddElement(ssrc,srcdat2)) < 0)
+ {
+ RTPDelete(srcdat2,GetMemoryManager());
+ return status;
+ }
+ *srcdat = srcdat2;
+ *created = true;
+ totalcount++;
+ }
+ else
+ {
+ *srcdat = sourcelist.GetCurrentElement();
+ *created = false;
+ }
+ return 0;
+}
+
+
+int RTPSources::GetRTCPSourceData(uint32_t ssrc,const RTPAddress *senderaddress,
+ RTPInternalSourceData **srcdat2,bool *newsource)
+{
+ int status;
+ bool created;
+ RTPInternalSourceData *srcdat;
+
+ *srcdat2 = 0;
+
+ if ((status = ObtainSourceDataInstance(ssrc,&srcdat,&created)) < 0)
+ return status;
+
+ if (created)
+ {
+ if ((status = srcdat->SetRTCPDataAddress(senderaddress)) < 0)
+ return status;
+ }
+ else // got a previously existing source
+ {
+ if (CheckCollision(srcdat,senderaddress,false))
+ return 0; // ignore packet on collision
+ }
+
+ *srcdat2 = srcdat;
+ *newsource = created;
+
+ return 0;
+}
+
+int RTPSources::UpdateReceiveTime(uint32_t ssrc,const RTPTime &receivetime,const RTPAddress *senderaddress)
+{
+ RTPInternalSourceData *srcdat;
+ bool created;
+ int status;
+
+ status = GetRTCPSourceData(ssrc,senderaddress,&srcdat,&created);
+ if (status < 0)
+ return status;
+ if (srcdat == 0)
+ return 0;
+
+ // We got valid SSRC info
+ srcdat->UpdateMessageTime(receivetime);
+
+ // Call the callback
+ if (created)
+ OnNewSource(srcdat);
+
+ return 0;
+}
+
+void RTPSources::Timeout(const RTPTime &curtime,const RTPTime &timeoutdelay)
+{
+ int newtotalcount = 0;
+ int newsendercount = 0;
+ int newactivecount = 0;
+ RTPTime checktime = curtime;
+ checktime -= timeoutdelay;
+
+ sourcelist.GotoFirstElement();
+ while (sourcelist.HasCurrentElement())
+ {
+ RTPInternalSourceData *srcdat = sourcelist.GetCurrentElement();
+ RTPTime lastmsgtime = srcdat->INF_GetLastMessageTime();
+
+ // we don't want to time out ourselves
+ if ((srcdat != owndata) && (lastmsgtime < checktime)) // timeout
+ {
+
+ totalcount--;
+ if (srcdat->IsSender())
+ sendercount--;
+ if (srcdat->IsActive())
+ activecount--;
+
+ sourcelist.DeleteCurrentElement();
+
+ OnTimeout(srcdat);
+ OnRemoveSource(srcdat);
+ RTPDelete(srcdat,GetMemoryManager());
+ }
+ else
+ {
+ newtotalcount++;
+ if (srcdat->IsSender())
+ newsendercount++;
+ if (srcdat->IsActive())
+ newactivecount++;
+ sourcelist.GotoNextElement();
+ }
+ }
+
+#ifdef RTPDEBUG
+ if (newtotalcount != totalcount)
+ {
+ std::cout << "New total count " << newtotalcount << " doesnt match old total count " << totalcount << std::endl;
+ SafeCountTotal();
+ }
+ if (newsendercount != sendercount)
+ {
+ std::cout << "New sender count " << newsendercount << " doesnt match old sender count " << sendercount << std::endl;
+ SafeCountSenders();
+ }
+ if (newactivecount != activecount)
+ {
+ std::cout << "New active count " << newactivecount << " doesnt match old active count " << activecount << std::endl;
+ SafeCountActive();
+ }
+#endif // RTPDEBUG
+
+ totalcount = newtotalcount; // just to play it safe
+ sendercount = newsendercount;
+ activecount = newactivecount;
+}
+
+void RTPSources::SenderTimeout(const RTPTime &curtime,const RTPTime &timeoutdelay)
+{
+ int newtotalcount = 0;
+ int newsendercount = 0;
+ int newactivecount = 0;
+ RTPTime checktime = curtime;
+ checktime -= timeoutdelay;
+
+ sourcelist.GotoFirstElement();
+ while (sourcelist.HasCurrentElement())
+ {
+ RTPInternalSourceData *srcdat = sourcelist.GetCurrentElement();
+
+ newtotalcount++;
+ if (srcdat->IsActive())
+ newactivecount++;
+
+ if (srcdat->IsSender())
+ {
+ RTPTime lastrtppacktime = srcdat->INF_GetLastRTPPacketTime();
+
+ if (lastrtppacktime < checktime) // timeout
+ {
+ srcdat->ClearSenderFlag();
+ sendercount--;
+ }
+ else
+ newsendercount++;
+ }
+ sourcelist.GotoNextElement();
+ }
+
+#ifdef RTPDEBUG
+ if (newtotalcount != totalcount)
+ {
+ std::cout << "New total count " << newtotalcount << " doesnt match old total count " << totalcount << std::endl;
+ SafeCountTotal();
+ }
+ if (newsendercount != sendercount)
+ {
+ std::cout << "New sender count " << newsendercount << " doesnt match old sender count " << sendercount << std::endl;
+ SafeCountSenders();
+ }
+ if (newactivecount != activecount)
+ {
+ std::cout << "New active count " << newactivecount << " doesnt match old active count " << activecount << std::endl;
+ SafeCountActive();
+ }
+#endif // RTPDEBUG
+
+ totalcount = newtotalcount; // just to play it safe
+ sendercount = newsendercount;
+ activecount = newactivecount;
+}
+
+void RTPSources::BYETimeout(const RTPTime &curtime,const RTPTime &timeoutdelay)
+{
+ int newtotalcount = 0;
+ int newsendercount = 0;
+ int newactivecount = 0;
+ RTPTime checktime = curtime;
+ checktime -= timeoutdelay;
+
+ sourcelist.GotoFirstElement();
+ while (sourcelist.HasCurrentElement())
+ {
+ RTPInternalSourceData *srcdat = sourcelist.GetCurrentElement();
+
+ if (srcdat->ReceivedBYE())
+ {
+ RTPTime byetime = srcdat->GetBYETime();
+
+ if ((srcdat != owndata) && (checktime > byetime))
+ {
+ totalcount--;
+ if (srcdat->IsSender())
+ sendercount--;
+ if (srcdat->IsActive())
+ activecount--;
+ sourcelist.DeleteCurrentElement();
+ OnBYETimeout(srcdat);
+ OnRemoveSource(srcdat);
+ RTPDelete(srcdat,GetMemoryManager());
+ }
+ else
+ {
+ newtotalcount++;
+ if (srcdat->IsSender())
+ newsendercount++;
+ if (srcdat->IsActive())
+ newactivecount++;
+ sourcelist.GotoNextElement();
+ }
+ }
+ else
+ {
+ newtotalcount++;
+ if (srcdat->IsSender())
+ newsendercount++;
+ if (srcdat->IsActive())
+ newactivecount++;
+ sourcelist.GotoNextElement();
+ }
+ }
+
+#ifdef RTPDEBUG
+ if (newtotalcount != totalcount)
+ {
+ std::cout << "New total count " << newtotalcount << " doesnt match old total count " << totalcount << std::endl;
+ SafeCountTotal();
+ }
+ if (newsendercount != sendercount)
+ {
+ std::cout << "New sender count " << newsendercount << " doesnt match old sender count " << sendercount << std::endl;
+ SafeCountSenders();
+ }
+ if (newactivecount != activecount)
+ {
+ std::cout << "New active count " << newactivecount << " doesnt match old active count " << activecount << std::endl;
+ SafeCountActive();
+ }
+#endif // RTPDEBUG
+
+ totalcount = newtotalcount; // just to play it safe
+ sendercount = newsendercount;
+ activecount = newactivecount;
+}
+
+void RTPSources::NoteTimeout(const RTPTime &curtime,const RTPTime &timeoutdelay)
+{
+ int newtotalcount = 0;
+ int newsendercount = 0;
+ int newactivecount = 0;
+ RTPTime checktime = curtime;
+ checktime -= timeoutdelay;
+
+ sourcelist.GotoFirstElement();
+ while (sourcelist.HasCurrentElement())
+ {
+ RTPInternalSourceData *srcdat = sourcelist.GetCurrentElement();
+ uint8_t *note;
+ size_t notelen;
+
+ note = srcdat->SDES_GetNote(&notelen);
+ if (notelen != 0) // Note has been set
+ {
+ RTPTime notetime = srcdat->INF_GetLastSDESNoteTime();
+
+ if (checktime > notetime)
+ {
+ srcdat->ClearNote();
+ OnNoteTimeout(srcdat);
+ }
+ }
+
+ newtotalcount++;
+ if (srcdat->IsSender())
+ newsendercount++;
+ if (srcdat->IsActive())
+ newactivecount++;
+ sourcelist.GotoNextElement();
+ }
+
+#ifdef RTPDEBUG
+ if (newtotalcount != totalcount)
+ {
+ std::cout << "New total count " << newtotalcount << " doesnt match old total count " << totalcount << std::endl;
+ SafeCountTotal();
+ }
+ if (newsendercount != sendercount)
+ {
+ std::cout << "New sender count " << newsendercount << " doesnt match old sender count " << sendercount << std::endl;
+ SafeCountSenders();
+ }
+ if (newactivecount != activecount)
+ {
+ std::cout << "New active count " << newactivecount << " doesnt match old active count " << activecount << std::endl;
+ SafeCountActive();
+ }
+#endif // RTPDEBUG
+
+ totalcount = newtotalcount; // just to play it safe
+ sendercount = newsendercount;
+ activecount = newactivecount;
+
+}
+
+void RTPSources::MultipleTimeouts(const RTPTime &curtime,const RTPTime &sendertimeout,const RTPTime &byetimeout,const RTPTime &generaltimeout,const RTPTime &notetimeout)
+{
+ int newtotalcount = 0;
+ int newsendercount = 0;
+ int newactivecount = 0;
+ RTPTime senderchecktime = curtime;
+ RTPTime byechecktime = curtime;
+ RTPTime generaltchecktime = curtime;
+ RTPTime notechecktime = curtime;
+ senderchecktime -= sendertimeout;
+ byechecktime -= byetimeout;
+ generaltchecktime -= generaltimeout;
+ notechecktime -= notetimeout;
+
+ sourcelist.GotoFirstElement();
+ while (sourcelist.HasCurrentElement())
+ {
+ RTPInternalSourceData *srcdat = sourcelist.GetCurrentElement();
+ bool deleted,issender,isactive;
+ bool byetimeout,normaltimeout,notetimeout;
+ uint8_t *note;
+ size_t notelen;
+
+ issender = srcdat->IsSender();
+ isactive = srcdat->IsActive();
+ deleted = false;
+ byetimeout = false;
+ normaltimeout = false;
+ notetimeout = false;
+
+ note = srcdat->SDES_GetNote(&notelen);
+ if (notelen != 0) // Note has been set
+ {
+ RTPTime notetime = srcdat->INF_GetLastSDESNoteTime();
+
+ if (notechecktime > notetime)
+ {
+ notetimeout = true;
+ srcdat->ClearNote();
+ }
+ }
+
+ if (srcdat->ReceivedBYE())
+ {
+ RTPTime byetime = srcdat->GetBYETime();
+
+ if ((srcdat != owndata) && (byechecktime > byetime))
+ {
+ sourcelist.DeleteCurrentElement();
+ deleted = true;
+ byetimeout = true;
+ }
+ }
+
+ if (!deleted)
+ {
+ RTPTime lastmsgtime = srcdat->INF_GetLastMessageTime();
+
+ if ((srcdat != owndata) && (lastmsgtime < generaltchecktime))
+ {
+ sourcelist.DeleteCurrentElement();
+ deleted = true;
+ normaltimeout = true;
+ }
+ }
+
+ if (!deleted)
+ {
+ newtotalcount++;
+
+ if (issender)
+ {
+ RTPTime lastrtppacktime = srcdat->INF_GetLastRTPPacketTime();
+
+ if (lastrtppacktime < senderchecktime)
+ {
+ srcdat->ClearSenderFlag();
+ sendercount--;
+ }
+ else
+ newsendercount++;
+ }
+
+ if (isactive)
+ newactivecount++;
+
+ if (notetimeout)
+ OnNoteTimeout(srcdat);
+
+ sourcelist.GotoNextElement();
+ }
+ else // deleted entry
+ {
+ if (issender)
+ sendercount--;
+ if (isactive)
+ activecount--;
+ totalcount--;
+
+ if (byetimeout)
+ OnBYETimeout(srcdat);
+ if (normaltimeout)
+ OnTimeout(srcdat);
+ OnRemoveSource(srcdat);
+ RTPDelete(srcdat,GetMemoryManager());
+ }
+ }
+
+#ifdef RTPDEBUG
+ if (newtotalcount != totalcount)
+ {
+ SafeCountTotal();
+ std::cout << "New total count " << newtotalcount << " doesnt match old total count " << totalcount << std::endl;
+ }
+ if (newsendercount != sendercount)
+ {
+ SafeCountSenders();
+ std::cout << "New sender count " << newsendercount << " doesnt match old sender count " << sendercount << std::endl;
+ }
+ if (newactivecount != activecount)
+ {
+ std::cout << "New active count " << newactivecount << " doesnt match old active count " << activecount << std::endl;
+ SafeCountActive();
+ }
+#endif // RTPDEBUG
+
+ totalcount = newtotalcount; // just to play it safe
+ sendercount = newsendercount;
+ activecount = newactivecount;
+}
+
+#ifdef RTPDEBUG
+void RTPSources::Dump()
+{
+ std::cout << "Total count: " << totalcount << std::endl;
+ std::cout << "Sender count: " << sendercount << std::endl;
+ std::cout << "Active count: " << activecount << std::endl;
+ if (GotoFirstSource())
+ {
+ do
+ {
+ RTPSourceData *s;
+ s = GetCurrentSourceInfo();
+ s->Dump();
+ std::cout << std::endl;
+ } while (GotoNextSource());
+ }
+}
+
+void RTPSources::SafeCountTotal()
+{
+ int count = 0;
+
+ if (GotoFirstSource())
+ {
+ do
+ {
+ count++;
+ } while (GotoNextSource());
+ }
+ std::cout << "Actual total count: " << count << std::endl;
+}
+
+void RTPSources::SafeCountSenders()
+{
+ int count = 0;
+
+ if (GotoFirstSource())
+ {
+ do
+ {
+ RTPSourceData *s;
+ s = GetCurrentSourceInfo();
+ if (s->IsSender())
+ count++;
+ } while (GotoNextSource());
+ }
+ std::cout << "Actual sender count: " << count << std::endl;
+}
+
+void RTPSources::SafeCountActive()
+{
+ int count = 0;
+
+ if (GotoFirstSource())
+ {
+ do
+ {
+ RTPSourceData *s;
+ s = GetCurrentSourceInfo();
+ if (s->IsActive())
+ count++;
+ } while (GotoNextSource());
+ }
+ std::cout << "Actual active count: " << count << std::endl;
+}
+
+#endif // RTPDEBUG
+
+bool RTPSources::CheckCollision(RTPInternalSourceData *srcdat,const RTPAddress *senderaddress,bool isrtp)
+{
+ bool isset,otherisset;
+ const RTPAddress *addr,*otheraddr;
+
+ if (isrtp)
+ {
+ isset = srcdat->IsRTPAddressSet();
+ addr = srcdat->GetRTPDataAddress();
+ otherisset = srcdat->IsRTCPAddressSet();
+ otheraddr = srcdat->GetRTCPDataAddress();
+ }
+ else
+ {
+ isset = srcdat->IsRTCPAddressSet();
+ addr = srcdat->GetRTCPDataAddress();
+ otherisset = srcdat->IsRTPAddressSet();
+ otheraddr = srcdat->GetRTPDataAddress();
+ }
+
+ if (!isset)
+ {
+ if (otherisset) // got other address, can check if it comes from same host
+ {
+ if (otheraddr == 0) // other came from our own session
+ {
+ if (senderaddress != 0)
+ {
+ OnSSRCCollision(srcdat,senderaddress,isrtp);
+ return true;
+ }
+
+ // Ok, store it
+
+ if (isrtp)
+ srcdat->SetRTPDataAddress(senderaddress);
+ else
+ srcdat->SetRTCPDataAddress(senderaddress);
+ }
+ else
+ {
+ if (!otheraddr->IsFromSameHost(senderaddress))
+ {
+ OnSSRCCollision(srcdat,senderaddress,isrtp);
+ return true;
+ }
+
+ // Ok, comes from same host, store the address
+
+ if (isrtp)
+ srcdat->SetRTPDataAddress(senderaddress);
+ else
+ srcdat->SetRTCPDataAddress(senderaddress);
+ }
+ }
+ else // no other address, store this one
+ {
+ if (isrtp)
+ srcdat->SetRTPDataAddress(senderaddress);
+ else
+ srcdat->SetRTCPDataAddress(senderaddress);
+ }
+ }
+ else // already got an address
+ {
+ if (addr == 0)
+ {
+ if (senderaddress != 0)
+ {
+ OnSSRCCollision(srcdat,senderaddress,isrtp);
+ return true;
+ }
+ }
+ else
+ {
+ if (!addr->IsSameAddress(senderaddress))
+ {
+ OnSSRCCollision(srcdat,senderaddress,isrtp);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/src/rtpsources.h b/src/rtpsources.h
new file mode 100644
index 0000000..9c4807a
--- /dev/null
+++ b/src/rtpsources.h
@@ -0,0 +1,360 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpsources.h
+ */
+
+#ifndef RTPSOURCES_H
+
+#define RTPSOURCES_H
+
+#include "rtpconfig.h"
+#include "rtpkeyhashtable.h"
+#include "rtcpsdespacket.h"
+#include "rtptypes.h"
+#include "rtpmemoryobject.h"
+
+#define RTPSOURCES_HASHSIZE 8317
+
+class RTPSources_GetHashIndex
+{
+public:
+ static int GetIndex(const uint32_t &ssrc) { return ssrc%RTPSOURCES_HASHSIZE; }
+};
+
+class RTPNTPTime;
+class RTPTransmitter;
+class RTCPAPPPacket;
+class RTPInternalSourceData;
+class RTPRawPacket;
+class RTPPacket;
+class RTPTime;
+class RTPAddress;
+class RTPSourceData;
+
+/** Represents a table in which information about the participating sources is kept.
+ * Represents a table in which information about the participating sources is kept. The class has member
+ * functions to process RTP and RTCP data and to iterate over the participants. Note that a NULL address
+ * is used to identify packets from our own session. The class also provides some overridable functions
+ * which can be used to catch certain events (new SSRC, SSRC collision, ...).
+ */
+class RTPSources : public RTPMemoryObject
+{
+public:
+ /** Type of probation to use for new sources. */
+ enum ProbationType
+ {
+ NoProbation, /**< Don't use the probation algorithm; accept RTP packets immediately. */
+ ProbationDiscard, /**< Discard incoming RTP packets originating from a source that's on probation. */
+ ProbationStore /**< Store incoming RTP packet from a source that's on probation for later retrieval. */
+ };
+
+ /** In the constructor you can select the probation type you'd like to use and also a memory manager. */
+ RTPSources(ProbationType = ProbationStore,RTPMemoryManager *mgr = 0);
+ virtual ~RTPSources();
+
+ /** Clears the source table. */
+ void Clear();
+#ifdef RTP_SUPPORT_PROBATION
+ /** Changes the current probation type. */
+ void SetProbationType(ProbationType probtype) { probationtype = probtype; }
+#endif // RTP_SUPPORT_PROBATION
+
+ /** Creates an entry for our own SSRC identifier. */
+ int CreateOwnSSRC(uint32_t ssrc);
+
+ /** Deletes the entry for our own SSRC identifier. */
+ int DeleteOwnSSRC();
+
+ /** This function should be called if our own session has sent an RTP packet.
+ * This function should be called if our own session has sent an RTP packet.
+ * For our own SSRC entry, the sender flag is updated based upon outgoing packets instead of incoming packets.
+ */
+ void SentRTPPacket();
+
+ /** Processes a raw packet \c rawpack.
+ * Processes a raw packet \c rawpack. The instance \c trans will be used to check if this
+ * packet is one of our own packets. The flag \c acceptownpackets indicates whether own packets should be
+ * accepted or ignored.
+ */
+ int ProcessRawPacket(RTPRawPacket *rawpack,RTPTransmitter *trans,bool acceptownpackets);
+
+ /** Processes a raw packet \c rawpack.
+ * Processes a raw packet \c rawpack. Every transmitter in the array \c trans of length \c numtrans
+ * is used to check if the packet is from our own session. The flag \c acceptownpackets indicates
+ * whether own packets should be accepted or ignored.
+ */
+ int ProcessRawPacket(RTPRawPacket *rawpack,RTPTransmitter *trans[],int numtrans,bool acceptownpackets);
+
+ /** Processes an RTPPacket instance \c rtppack which was received at time \c receivetime and
+ * which originated from \c senderaddres.
+ * Processes an RTPPacket instance \c rtppack which was received at time \c receivetime and
+ * which originated from \c senderaddres. The \c senderaddress parameter must be NULL if
+ * the packet was sent by the local participant. The flag \c stored indicates whether the packet
+ * was stored in the table or not. If so, the \c rtppack instance may not be deleted.
+ */
+ int ProcessRTPPacket(RTPPacket *rtppack,const RTPTime &receivetime,const RTPAddress *senderaddress,bool *stored);
+
+ /** Processes the RTCP compound packet \c rtcpcomppack which was received at time \c receivetime from \c senderaddress.
+ * Processes the RTCP compound packet \c rtcpcomppack which was received at time \c receivetime from \c senderaddress.
+ * The \c senderaddress parameter must be NULL if the packet was sent by the local participant.
+ */
+ int ProcessRTCPCompoundPacket(RTCPCompoundPacket *rtcpcomppack,const RTPTime &receivetime,
+ const RTPAddress *senderaddress);
+
+ /** Process the sender information of SSRC \c ssrc into the source table.
+ * Process the sender information of SSRC \c ssrc into the source table. The information was received
+ * at time \c receivetime from address \c senderaddress. The \c senderaddress} parameter must be NULL
+ * if the packet was sent by the local participant.
+ */
+ int ProcessRTCPSenderInfo(uint32_t ssrc,const RTPNTPTime &ntptime,uint32_t rtptime,
+ uint32_t packetcount,uint32_t octetcount,const RTPTime &receivetime,
+ const RTPAddress *senderaddress);
+
+ /** Processes the report block information which was sent by participant \c ssrc into the source table.
+ * Processes the report block information which was sent by participant \c ssrc into the source table.
+ * The information was received at time \c receivetime from address \c senderaddress The \c senderaddress
+ * parameter must be NULL if the packet was sent by the local participant.
+ */
+ int ProcessRTCPReportBlock(uint32_t ssrc,uint8_t fractionlost,int32_t lostpackets,
+ uint32_t exthighseqnr,uint32_t jitter,uint32_t lsr,
+ uint32_t dlsr,const RTPTime &receivetime,const RTPAddress *senderaddress);
+
+ /** Processes the non-private SDES item from source \c ssrc into the source table.
+ * Processes the non-private SDES item from source \c ssrc into the source table. The information was
+ * received at time \c receivetime from address \c senderaddress. The \c senderaddress parameter must
+ * be NULL if the packet was sent by the local participant.
+ */
+ int ProcessSDESNormalItem(uint32_t ssrc,RTCPSDESPacket::ItemType t,size_t itemlength,
+ const void *itemdata,const RTPTime &receivetime,const RTPAddress *senderaddress);
+#ifdef RTP_SUPPORT_SDESPRIV
+ /** Processes the SDES private item from source \c ssrc into the source table.
+ * Processes the SDES private item from source \c ssrc into the source table. The information was
+ * received at time \c receivetime from address \c senderaddress. The \c senderaddress
+ * parameter must be NULL if the packet was sent by the local participant.
+ */
+ int ProcessSDESPrivateItem(uint32_t ssrc,size_t prefixlen,const void *prefixdata,
+ size_t valuelen,const void *valuedata,const RTPTime &receivetime,
+ const RTPAddress *senderaddress);
+#endif //RTP_SUPPORT_SDESPRIV
+ /** Processes the BYE message for SSRC \c ssrc.
+ * Processes the BYE message for SSRC \c ssrc. The information was received at time \c receivetime from
+ * address \c senderaddress. The \c senderaddress parameter must be NULL if the packet was sent by the
+ * local participant.
+ */
+ int ProcessBYE(uint32_t ssrc,size_t reasonlength,const void *reasondata,const RTPTime &receivetime,
+ const RTPAddress *senderaddress);
+
+ /** If we heard from source \c ssrc, but no actual data was added to the source table (for example, if
+ * no report block was meant for us), this function can e used to indicate that something was received from
+ * this source.
+ * If we heard from source \c ssrc, but no actual data was added to the source table (for example, if
+ * no report block was meant for us), this function can e used to indicate that something was received from
+ * this source. This will prevent a premature timeout for this participant. The message was received at time
+ * \c receivetime from address \c senderaddress. The \c senderaddress parameter must be NULL if the
+ * packet was sent by the local participant.
+ */
+ int UpdateReceiveTime(uint32_t ssrc,const RTPTime &receivetime,const RTPAddress *senderaddress);
+
+ /** Starts the iteration over the participants by going to the first member in the table.
+ * Starts the iteration over the participants by going to the first member in the table.
+ * If a member was found, the function returns \c true, otherwise it returns \c false.
+ */
+ bool GotoFirstSource();
+
+ /** Sets the current source to be the next source in the table.
+ * Sets the current source to be the next source in the table. If we're already at the last source,
+ * the function returns \c false, otherwise it returns \c true.
+ */
+ bool GotoNextSource();
+
+ /** Sets the current source to be the previous source in the table.
+ * Sets the current source to be the previous source in the table. If we're at the first source,
+ * the function returns \c false, otherwise it returns \c true.
+ */
+ bool GotoPreviousSource();
+
+ /** Sets the current source to be the first source in the table which has RTPPacket instances
+ * that we haven't extracted yet.
+ * Sets the current source to be the first source in the table which has RTPPacket instances
+ * that we haven't extracted yet. If no such member was found, the function returns \c false,
+ * otherwise it returns \c true.
+ */
+ bool GotoFirstSourceWithData();
+
+ /** Sets the current source to be the next source in the table which has RTPPacket instances that
+ * we haven't extracted yet.
+ * Sets the current source to be the next source in the table which has RTPPacket instances that
+ * we haven't extracted yet. If no such member was found, the function returns \c false,
+ * otherwise it returns \c true.
+ */
+ bool GotoNextSourceWithData();
+
+ /** Sets the current source to be the previous source in the table which has RTPPacket instances
+ * that we haven't extracted yet.
+ * Sets the current source to be the previous source in the table which has RTPPacket instances
+ * that we haven't extracted yet. If no such member was found, the function returns \c false,
+ * otherwise it returns \c true.
+ */
+ bool GotoPreviousSourceWithData();
+
+ /** Returns the RTPSourceData instance for the currently selected participant. */
+ RTPSourceData *GetCurrentSourceInfo();
+
+ /** Returns the RTPSourceData instance for the participant identified by \c ssrc, or
+ * NULL if no such entry exists.
+ */
+ RTPSourceData *GetSourceInfo(uint32_t ssrc);
+
+ /** Extracts the next packet from the received packets queue of the current participant. */
+ RTPPacket *GetNextPacket();
+
+ /** Returns \c true if an entry for participant \c ssrc exists and \c false otherwise. */
+ bool GotEntry(uint32_t ssrc);
+
+ /** If present, it returns the RTPSourceData instance of the entry which was created by CreateOwnSSRC. */
+ RTPSourceData *GetOwnSourceInfo() { return (RTPSourceData *)owndata; }
+
+ /** Assuming that the current time is \c curtime, time out the members from whom we haven't heard
+ * during the previous time interval \c timeoutdelay.
+ */
+ void Timeout(const RTPTime &curtime,const RTPTime &timeoutdelay);
+
+ /** Assuming that the current time is \c curtime, remove the sender flag for senders from whom we haven't
+ * received any RTP packets during the previous time interval \c timeoutdelay.
+ */
+ void SenderTimeout(const RTPTime &curtime,const RTPTime &timeoutdelay);
+
+ /** Assuming that the current time is \c curtime, remove the members who sent a BYE packet more than
+ * the time interval \c timeoutdelay ago.
+ */
+ void BYETimeout(const RTPTime &curtime,const RTPTime &timeoutdelay);
+
+ /** Assuming that the current time is \c curtime, clear the SDES NOTE items which haven't been updated
+ * during the previous time interval \c timeoutdelay.
+ */
+ void NoteTimeout(const RTPTime &curtime,const RTPTime &timeoutdelay);
+
+ /** Combines the functions SenderTimeout, BYETimeout, Timeout and NoteTimeout.
+ * Combines the functions SenderTimeout, BYETimeout, Timeout and NoteTimeout. This is more efficient
+ * than calling all four functions since only one iteration is needed in this function.
+ */
+ void MultipleTimeouts(const RTPTime &curtime,const RTPTime &sendertimeout,
+ const RTPTime &byetimeout,const RTPTime &generaltimeout,
+ const RTPTime &notetimeout);
+
+ /** Returns the number of participants which are marked as a sender. */
+ int GetSenderCount() const { return sendercount; }
+
+ /** Returns the total number of entries in the source table. */
+ int GetTotalCount() const { return totalcount; }
+
+ /** Returns the number of members which have been validated and which haven't sent a BYE packet yet. */
+ int GetActiveMemberCount() const { return activecount; }
+#ifdef RTPDEBUG
+ void Dump();
+ void SafeCountTotal();
+ void SafeCountSenders();
+ void SafeCountActive();
+#endif // RTPDEBUG
+protected:
+ /** Is called when an RTP packet is about to be processed. */
+ virtual void OnRTPPacket(RTPPacket *pack,const RTPTime &receivetime, const RTPAddress *senderaddress) { }
+
+ /** Is called when an RTCP compound packet is about to be processed. */
+ virtual void OnRTCPCompoundPacket(RTCPCompoundPacket *pack,const RTPTime &receivetime,
+ const RTPAddress *senderaddress) { }
+
+ /** Is called when an SSRC collision was detected.
+ * Is called when an SSRC collision was detected. The instance \c srcdat is the one present in
+ * the table, the address \c senderaddress is the one that collided with one of the addresses
+ * and \c isrtp indicates against which address of \c srcdat the check failed.
+ */
+ virtual void OnSSRCCollision(RTPSourceData *srcdat,const RTPAddress *senderaddress,bool isrtp) { }
+
+ /** Is called when another CNAME was received than the one already present for source \c srcdat. */
+ virtual void OnCNAMECollision(RTPSourceData *srcdat,const RTPAddress *senderaddress,
+ const uint8_t *cname,size_t cnamelength) { }
+
+ /** Is called when a new entry \c srcdat is added to the source table. */
+ virtual void OnNewSource(RTPSourceData *srcdat) { }
+
+ /** Is called when the entry \c srcdat is about to be deleted from the source table. */
+ virtual void OnRemoveSource(RTPSourceData *srcdat) { }
+
+ /** Is called when participant \c srcdat is timed out. */
+ virtual void OnTimeout(RTPSourceData *srcdat) { }
+
+ /** Is called when participant \c srcdat is timed after having sent a BYE packet. */
+ virtual void OnBYETimeout(RTPSourceData *srcdat) { }
+
+ /** Is called when a BYE packet has been processed for source \c srcdat. */
+ virtual void OnBYEPacket(RTPSourceData *srcdat) { }
+
+ /** Is called when an RTCP APP packet \c apppacket has been received at time \c receivetime
+ * from address \c senderaddress.
+ */
+ virtual void OnAPPPacket(RTCPAPPPacket *apppacket,const RTPTime &receivetime,
+ const RTPAddress *senderaddress) { }
+
+ /** Is called when an unknown RTCP packet type was detected. */
+ virtual void OnUnknownPacketType(RTCPPacket *rtcppack,const RTPTime &receivetime,
+ const RTPAddress *senderaddress) { }
+
+ /** Is called when an unknown packet format for a known packet type was detected. */
+ virtual void OnUnknownPacketFormat(RTCPPacket *rtcppack,const RTPTime &receivetime,
+ const RTPAddress *senderaddress) { }
+
+ /** Is called when the SDES NOTE item for source \c srcdat has been timed out. */
+ virtual void OnNoteTimeout(RTPSourceData *srcdat) { }
+private:
+ void ClearSourceList();
+ int ObtainSourceDataInstance(uint32_t ssrc,RTPInternalSourceData **srcdat,bool *created);
+ int GetRTCPSourceData(uint32_t ssrc,const RTPAddress *senderaddress,RTPInternalSourceData **srcdat,bool *newsource);
+ bool CheckCollision(RTPInternalSourceData *srcdat,const RTPAddress *senderaddress,bool isrtp);
+
+ RTPKeyHashTable<const uint32_t,RTPInternalSourceData*,RTPSources_GetHashIndex,RTPSOURCES_HASHSIZE> sourcelist;
+
+ int sendercount;
+ int totalcount;
+ int activecount;
+
+#ifdef RTP_SUPPORT_PROBATION
+ ProbationType probationtype;
+#endif // RTP_SUPPORT_PROBATION
+
+ RTPInternalSourceData *owndata;
+};
+
+#endif // RTPSOURCES_H
+
diff --git a/src/rtpstructs.h b/src/rtpstructs.h
new file mode 100644
index 0000000..3c0fa2d
--- /dev/null
+++ b/src/rtpstructs.h
@@ -0,0 +1,123 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpstructs.h
+ */
+
+#ifndef RTPSTRUCTS_H
+
+#define RTPSTRUCTS_H
+
+#include "rtpconfig.h"
+#include "rtptypes.h"
+
+struct RTPHeader
+{
+#ifdef RTP_BIG_ENDIAN
+ uint8_t version:2;
+ uint8_t padding:1;
+ uint8_t extension:1;
+ uint8_t csrccount:4;
+
+ uint8_t marker:1;
+ uint8_t payloadtype:7;
+#else // little endian
+ uint8_t csrccount:4;
+ uint8_t extension:1;
+ uint8_t padding:1;
+ uint8_t version:2;
+
+ uint8_t payloadtype:7;
+ uint8_t marker:1;
+#endif // RTP_BIG_ENDIAN
+
+ uint16_t sequencenumber;
+ uint32_t timestamp;
+ uint32_t ssrc;
+};
+
+struct RTPExtensionHeader
+{
+ uint16_t extid;
+ uint16_t length;
+};
+
+struct RTPSourceIdentifier
+{
+ uint32_t ssrc;
+};
+
+struct RTCPCommonHeader
+{
+#ifdef RTP_BIG_ENDIAN
+ uint8_t version:2;
+ uint8_t padding:1;
+ uint8_t count:5;
+#else // little endian
+ uint8_t count:5;
+ uint8_t padding:1;
+ uint8_t version:2;
+#endif // RTP_BIG_ENDIAN
+
+ uint8_t packettype;
+ uint16_t length;
+};
+
+struct RTCPSenderReport
+{
+ uint32_t ntptime_msw;
+ uint32_t ntptime_lsw;
+ uint32_t rtptimestamp;
+ uint32_t packetcount;
+ uint32_t octetcount;
+};
+
+struct RTCPReceiverReport
+{
+ uint32_t ssrc; // Identifies about which SSRC's data this report is...
+ uint8_t fractionlost;
+ uint8_t packetslost[3];
+ uint32_t exthighseqnr;
+ uint32_t jitter;
+ uint32_t lsr;
+ uint32_t dlsr;
+};
+
+struct RTCPSDESHeader
+{
+ uint8_t sdesid;
+ uint8_t length;
+};
+
+#endif // RTPSTRUCTS
+
diff --git a/src/rtptimeutilities.cpp b/src/rtptimeutilities.cpp
new file mode 100644
index 0000000..f8f0dd3
--- /dev/null
+++ b/src/rtptimeutilities.cpp
@@ -0,0 +1,52 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#if (defined(WIN32) || defined(_WIN32_WCE))
+
+#include "rtptimeutilities.h"
+#ifdef RTPDEBUG
+ #include <iostream>
+#endif // RTPDEBUG
+
+RTPTimeInitializer::RTPTimeInitializer()
+{
+#ifdef RTPDEBUG
+ std::cout << "RTPTimeInitializer: Initializing RTPTime::CurrentTime()" << std::endl;
+#endif // RTPDEBUG
+ RTPTime curtime = RTPTime::CurrentTime();
+ dummy = -1;
+}
+
+RTPTimeInitializer timeinit;
+
+#endif // WIN32 || _WIN32_WCE
+
diff --git a/src/rtptimeutilities.h b/src/rtptimeutilities.h
new file mode 100644
index 0000000..527ef87
--- /dev/null
+++ b/src/rtptimeutilities.h
@@ -0,0 +1,319 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtptimeutilities.h
+ */
+
+#ifndef RTPTIMEUTILITIES_H
+
+#define RTPTIMEUTILITIES_H
+
+#include "rtpconfig.h"
+#include "rtptypes.h"
+#ifndef WIN32
+ #include <sys/time.h>
+ #include <time.h>
+#else
+ #ifndef _WIN32_WCE
+ #include <sys/timeb.h>
+ #endif // _WIN32_WINCE
+#endif // WIN32
+
+#define RTP_NTPTIMEOFFSET 2208988800UL
+
+/**
+ * This is a simple wrapper for the most significant word (MSW) and least
+ * significant word (LSW) of an NTP timestamp.
+ */
+class RTPNTPTime
+{
+public:
+ /** This constructor creates and instance with MSW \c m and LSW \c l. */
+ RTPNTPTime(uint32_t m,uint32_t l) { msw = m ; lsw = l; }
+
+ /** Returns the most significant word. */
+ uint32_t GetMSW() const { return msw; }
+
+ /** Returns the least significant word. */
+ uint32_t GetLSW() const { return lsw; }
+private:
+ uint32_t msw,lsw;
+};
+
+/** This class is used to specify wallclock time, delay intervals etc.
+ * This class is used to specify wallclock time, delay intervals etc.
+ * It stores a number of seconds and a number of microseconds.
+ */
+class RTPTime
+{
+public:
+ /** Returns an RTPTime instance representing the current wallclock time.
+ * Returns an RTPTime instance representing the current wallclock time. This is expressed
+ * as a number of seconds since 00:00:00 UTC, January 1, 1970.
+ */
+ static RTPTime CurrentTime();
+
+ /** This function waits the amount of time specified in \c delay. */
+ static void Wait(const RTPTime &delay);
+
+ /** Creates an RTPTime instance representing \c t, which is expressed in units of seconds. */
+ RTPTime(double t);
+
+ /** Creates an instance that corresponds to \c ntptime.
+ * Creates an instance that corresponds to \c ntptime. If
+ * the conversion cannot be made, both the seconds and the
+ * microseconds are set to zero.
+ */
+ RTPTime(RTPNTPTime ntptime);
+
+ /** Creates an instance corresponding to \c seconds and \c microseconds. */
+ RTPTime(uint32_t seconds,uint32_t microseconds) { sec = seconds; microsec = microseconds; }
+
+ /** Returns the number of seconds stored in this instance. */
+ uint32_t GetSeconds() const { return sec; }
+
+ /** Returns the number of microseconds stored in this instance. */
+ uint32_t GetMicroSeconds() const { return microsec; }
+
+ /** Returns the time stored in this instance, expressed in units of seconds. */
+ double GetDouble() const { return (((double)sec)+(((double)microsec)/1000000.0)); }
+
+ /** Returns the NTP time corresponding to the time stored in this instance. */
+ RTPNTPTime GetNTPTime() const;
+
+ RTPTime &operator-=(const RTPTime &t);
+ RTPTime &operator+=(const RTPTime &t);
+ bool operator<(const RTPTime &t) const;
+ bool operator>(const RTPTime &t) const;
+ bool operator<=(const RTPTime &t) const;
+ bool operator>=(const RTPTime &t) const;
+private:
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ static inline unsigned __int64 CalculateMicroseconds(unsigned __int64 performancecount,unsigned __int64 performancefrequency);
+#endif // WIN32 || _WIN32_WCE
+
+ uint32_t sec,microsec;
+};
+
+inline RTPTime::RTPTime(double t)
+{
+ sec = (uint32_t)t;
+
+ double t2 = t-((double)sec);
+ t2 *= 1000000.0;
+ microsec = (uint32_t)t2;
+}
+
+inline RTPTime::RTPTime(RTPNTPTime ntptime)
+{
+ if (ntptime.GetMSW() < RTP_NTPTIMEOFFSET)
+ {
+ sec = 0;
+ microsec = 0;
+ }
+ else
+ {
+ sec = ntptime.GetMSW() - RTP_NTPTIMEOFFSET;
+
+ double x = (double)ntptime.GetLSW();
+ x /= (65536.0*65536.0);
+ x *= 1000000.0;
+ microsec = (uint32_t)x;
+ }
+}
+
+#if (defined(WIN32) || defined(_WIN32_WCE))
+
+inline unsigned __int64 RTPTime::CalculateMicroseconds(unsigned __int64 performancecount,unsigned __int64 performancefrequency)
+{
+ unsigned __int64 f = performancefrequency;
+ unsigned __int64 a = performancecount;
+ unsigned __int64 b = a/f;
+ unsigned __int64 c = a%f; // a = b*f+c => (a*1000000)/f = b*1000000+(c*1000000)/f
+
+ return b*1000000ui64+(c*1000000ui64)/f;
+}
+
+inline RTPTime RTPTime::CurrentTime()
+{
+ static int inited = 0;
+ static unsigned __int64 microseconds, initmicroseconds;
+ static LARGE_INTEGER performancefrequency;
+
+ unsigned __int64 emulate_microseconds, microdiff;
+ SYSTEMTIME systemtime;
+ FILETIME filetime;
+
+ LARGE_INTEGER performancecount;
+
+ QueryPerformanceCounter(&performancecount);
+
+ if(!inited){
+ inited = 1;
+ QueryPerformanceFrequency(&performancefrequency);
+ GetSystemTime(&systemtime);
+ SystemTimeToFileTime(&systemtime,&filetime);
+ microseconds = ( ((unsigned __int64)(filetime.dwHighDateTime) << 32) + (unsigned __int64)(filetime.dwLowDateTime) ) / 10ui64;
+ microseconds-= 11644473600000000ui64; // EPOCH
+ initmicroseconds = CalculateMicroseconds(performancecount.QuadPart, performancefrequency.QuadPart);
+ }
+
+ emulate_microseconds = CalculateMicroseconds(performancecount.QuadPart, performancefrequency.QuadPart);
+
+ microdiff = emulate_microseconds - initmicroseconds;
+
+ return RTPTime((uint32_t)((microseconds + microdiff) / 1000000ui64),((uint32_t)((microseconds + microdiff) % 1000000ui64)));
+}
+
+inline void RTPTime::Wait(const RTPTime &delay)
+{
+ DWORD t;
+
+ t = ((DWORD)delay.GetSeconds())*1000+(((DWORD)delay.GetMicroSeconds())/1000);
+ Sleep(t);
+}
+
+class RTPTimeInitializer
+{
+public:
+ RTPTimeInitializer();
+ void Dummy() { dummy++; }
+private:
+ int dummy;
+};
+
+extern RTPTimeInitializer timeinit;
+
+#else // unix style
+
+inline RTPTime RTPTime::CurrentTime()
+{
+ struct timeval tv;
+
+ gettimeofday(&tv,0);
+ return RTPTime((uint32_t)tv.tv_sec,(uint32_t)tv.tv_usec);
+}
+
+inline void RTPTime::Wait(const RTPTime &delay)
+{
+ struct timespec req,rem;
+
+ req.tv_sec = (time_t)delay.sec;
+ req.tv_nsec = ((long)delay.microsec)*1000;
+ nanosleep(&req,&rem);
+}
+
+#endif // WIN32
+
+inline RTPTime &RTPTime::operator-=(const RTPTime &t)
+{
+ sec -= t.sec;
+ if (t.microsec > microsec)
+ {
+ sec--;
+ microsec += 1000000;
+ }
+ microsec -= t.microsec;
+ return *this;
+}
+
+inline RTPTime &RTPTime::operator+=(const RTPTime &t)
+{
+ sec += t.sec;
+ microsec += t.microsec;
+ if (microsec >= 1000000)
+ {
+ sec++;
+ microsec -= 1000000;
+ }
+ return *this;
+}
+
+inline RTPNTPTime RTPTime::GetNTPTime() const
+{
+ uint32_t msw = sec+RTP_NTPTIMEOFFSET;
+ uint32_t lsw;
+ double x;
+
+ x = microsec/1000000.0;
+ x *= (65536.0*65536.0);
+ lsw = (uint32_t)x;
+
+ return RTPNTPTime(msw,lsw);
+}
+
+inline bool RTPTime::operator<(const RTPTime &t) const
+{
+ if (sec < t.sec)
+ return true;
+ if (sec > t.sec)
+ return false;
+ if (microsec < t.microsec)
+ return true;
+ return false;
+}
+
+inline bool RTPTime::operator>(const RTPTime &t) const
+{
+ if (sec > t.sec)
+ return true;
+ if (sec < t.sec)
+ return false;
+ if (microsec > t.microsec)
+ return true;
+ return false;
+}
+
+inline bool RTPTime::operator<=(const RTPTime &t) const
+{
+ if (sec < t.sec)
+ return true;
+ if (sec > t.sec)
+ return false;
+ if (microsec <= t.microsec)
+ return true;
+ return false;
+}
+
+inline bool RTPTime::operator>=(const RTPTime &t) const
+{
+ if (sec > t.sec)
+ return true;
+ if (sec < t.sec)
+ return false;
+ if (microsec >= t.microsec)
+ return true;
+ return false;
+}
+#endif // RTPTIMEUTILITIES_H
+
diff --git a/src/rtptransmitter.h b/src/rtptransmitter.h
new file mode 100644
index 0000000..bd2f3ea
--- /dev/null
+++ b/src/rtptransmitter.h
@@ -0,0 +1,249 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtptransmitter.h
+ */
+
+#ifndef RTPTRANSMITTER_H
+
+#define RTPTRANSMITTER_H
+
+#include "rtpconfig.h"
+#include "rtptypes.h"
+#include "rtpmemoryobject.h"
+
+class RTPRawPacket;
+class RTPAddress;
+class RTPTransmissionParams;
+class RTPTime;
+class RTPTransmissionInfo;
+
+/** Abstract class from which actual transmission components should be derived.
+ * Abstract class from which actual transmission components should be derived.
+ * The abstract class RTPTransmitter specifies the interface for
+ * actual transmission components. Currently, two implementations exist:
+ * an UDP over IPv4 transmitter and an UDP over IPv6 transmitter.
+ */
+class RTPTransmitter : public RTPMemoryObject
+{
+public:
+ /** Used to identify a specific transmitter.
+ * If UserDefinedProto is used in the RTPSession::Create function, the RTPSession
+ * virtual member function NewUserDefinedTransmitter will be called to create
+ * a transmission component.
+ */
+ enum TransmissionProtocol
+ {
+ IPv4UDPProto, /**< Specifies the internal UDP over IPv4 transmitter. */
+ IPv6UDPProto, /**< Specifies the internal UDP over IPv6 transmitter. */
+ UserDefinedProto /**< Specifies a user defined, external transmitter. */
+ };
+
+ /** Three kind of receive modes can be specified. */
+ enum ReceiveMode
+ {
+ AcceptAll, /**< All incoming data is accepted, no matter where it originated from. */
+ AcceptSome, /**< Only data coming from specific sources will be accepted. */
+ IgnoreSome /**< All incoming data is accepted, except for data coming from a specific set of sources. */
+ };
+protected:
+ /** Constructor in which you can specify a memory manager to use. */
+ RTPTransmitter(RTPMemoryManager *mgr) : RTPMemoryObject(mgr) { }
+public:
+ virtual ~RTPTransmitter() { }
+
+ /** This function must be called before the transmission component can be used.
+ * This function must be called before the transmission component can be used. Depending on
+ * the value of \c threadsafe, the component will be created for thread-safe usage or not.
+ */
+ virtual int Init(bool threadsafe) = 0;
+
+ /** Prepares the component to be used.
+ * Prepares the component to be used. The parameter \c maxpacksize specifies the maximum size
+ * a packet can have: if the packet is larger it will not be transmitted. The \c transparams
+ * parameter specifies a pointer to an RTPTransmissionParams instance. This is also an abstract
+ * class and each actual component will define its own parameters by inheriting a class
+ * from RTPTransmissionParams. If \c transparams is NULL, the default transmission parameters
+ * for the component will be used.
+ */
+ virtual int Create(size_t maxpacksize,const RTPTransmissionParams *transparams) = 0;
+
+ /** By calling this function, buffers are cleared and the component cannot be used anymore.
+ * By calling this function, buffers are cleared and the component cannot be used anymore.
+ * Only when the Create function is called again can the component be used again. */
+ virtual void Destroy() = 0;
+
+ /** Returns additional information about the transmitter.
+ * This function returns an instance of a subclass of RTPTransmissionInfo which will give
+ * some additional information about the transmitter (a list of local IP addresses for example).
+ * Currently, either an instance of RTPUDPv4TransmissionInfo or RTPUDPv6TransmissionInfo is
+ * returned, depending on the type of the transmitter. The user has to deallocate the returned
+ * instance when it is no longer needed.
+ */
+ virtual RTPTransmissionInfo *GetTransmissionInfo() = 0;
+
+ /** Looks up the local host name.
+ * Looks up the local host name based upon internal information about the local host's
+ * addresses. This function might take some time since a DNS query might be done. \c bufferlength
+ * should initially contain the number of bytes that may be stored in \c buffer. If the function
+ * succeeds, \c bufferlength is set to the number of bytes stored in \c buffer. Note that the data
+ * in \c buffer is not NULL-terminated. If the function fails because the buffer isn't large enough,
+ * it returns \c ERR_RTP_TRANS_BUFFERLENGTHTOOSMALL and stores the number of bytes needed in
+ * \c bufferlength.
+ */
+ virtual int GetLocalHostName(uint8_t *buffer,size_t *bufferlength) = 0;
+
+ /** Returns \c true if the address specified by \c addr is one of the addresses of the transmitter. */
+ virtual bool ComesFromThisTransmitter(const RTPAddress *addr) = 0;
+
+ /** Returns the amount of bytes that will be added to the RTP packet by the underlying layers (excluding
+ * the link layer). */
+ virtual size_t GetHeaderOverhead() = 0;
+
+ /** Checks for incoming data and stores it. */
+ virtual int Poll() = 0;
+
+ /** Waits until incoming data is detected.
+ * Waits at most a time \c delay until incoming data has been detected. If \c dataavailable is not NULL,
+ * it should be set to \c true if data was actually read and to \c false otherwise.
+ */
+ virtual int WaitForIncomingData(const RTPTime &delay,bool *dataavailable = 0) = 0;
+
+ /** If the previous function has been called, this one aborts the waiting. */
+ virtual int AbortWait() = 0;
+
+ /** Send a packet with length \c len containing \c data to all RTP addresses of the current destination list. */
+ virtual int SendRTPData(const void *data,size_t len) = 0;
+
+ /** Send a packet with length \c len containing \c data to all RTCP addresses of the current destination list. */
+ virtual int SendRTCPData(const void *data,size_t len) = 0;
+
+ /** Adds the address specified by \c addr to the list of destinations. */
+ virtual int AddDestination(const RTPAddress &addr) = 0;
+
+ /** Deletes the address specified by \c addr from the list of destinations. */
+ virtual int DeleteDestination(const RTPAddress &addr) = 0;
+
+ /** Clears the list of destinations. */
+ virtual void ClearDestinations() = 0;
+
+ /** Returns \c true if the transmission component supports multicasting. */
+ virtual bool SupportsMulticasting() = 0;
+
+ /** Joins the multicast group specified by \c addr. */
+ virtual int JoinMulticastGroup(const RTPAddress &addr) = 0;
+
+ /** Leaves the multicast group specified by \c addr. */
+ virtual int LeaveMulticastGroup(const RTPAddress &addr) = 0;
+
+ /** Leaves all the multicast groups that have been joined. */
+ virtual void LeaveAllMulticastGroups() = 0;
+
+ /** Sets the receive mode.
+ * Sets the receive mode to \c m, which is one of the following: RTPTransmitter::AcceptAll,
+ * RTPTransmitter::AcceptSome or RTPTransmitter::IgnoreSome. Note that if the receive
+ * mode is changed, all information about the addresses to ignore to accept is lost.
+ */
+ virtual int SetReceiveMode(RTPTransmitter::ReceiveMode m) = 0;
+
+ /** Adds \c addr to the list of addresses to ignore. */
+ virtual int AddToIgnoreList(const RTPAddress &addr) = 0;
+
+ /** Deletes \c addr from the list of addresses to accept. */
+ virtual int DeleteFromIgnoreList(const RTPAddress &addr)= 0;
+
+ /** Clears the list of addresses to ignore. */
+ virtual void ClearIgnoreList() = 0;
+
+ /** Adds \c addr to the list of addresses to accept. */
+ virtual int AddToAcceptList(const RTPAddress &addr) = 0;
+
+ /** Deletes \c addr from the list of addresses to accept. */
+ virtual int DeleteFromAcceptList(const RTPAddress &addr) = 0;
+
+ /** Clears the list of addresses to accept. */
+ virtual void ClearAcceptList() = 0;
+
+ /** Sets the maximum packet size which the transmitter should allow to \c s. */
+ virtual int SetMaximumPacketSize(size_t s) = 0;
+
+ /** Returns \c true if packets can be obtained using the GetNextPacket member function. */
+ virtual bool NewDataAvailable() = 0;
+
+ /** Returns the raw data of a received RTP packet (received during the Poll function)
+ * in an RTPRawPacket instance. */
+ virtual RTPRawPacket *GetNextPacket() = 0;
+#ifdef RTPDEBUG
+ virtual void Dump() = 0;
+#endif // RTPDEBUG
+};
+
+/** Base class for transmission parameters.
+ * This class is an abstract class which will have a specific implementation for a
+ * specific kind of transmission component. All actual implementations inherit the
+ * GetTransmissionProtocol function which identifies the component type for which
+ * these parameters are valid.
+ */
+class RTPTransmissionParams
+{
+protected:
+ RTPTransmissionParams(RTPTransmitter::TransmissionProtocol p) { protocol = p; }
+public:
+ virtual ~RTPTransmissionParams() { }
+
+ /** Returns the transmitter type for which these parameters are valid. */
+ RTPTransmitter::TransmissionProtocol GetTransmissionProtocol() const { return protocol; }
+private:
+ RTPTransmitter::TransmissionProtocol protocol;
+};
+
+/** Base class for additional information about the transmitter.
+ * This class is an abstract class which will have a specific implementation for a
+ * specific kind of transmission component. All actual implementations inherit the
+ * GetTransmissionProtocol function which identifies the component type for which
+ * these parameters are valid.
+ */
+class RTPTransmissionInfo
+{
+protected:
+ RTPTransmissionInfo(RTPTransmitter::TransmissionProtocol p) { protocol = p; }
+public:
+ virtual ~RTPTransmissionInfo() { }
+ /** Returns the transmitter type for which these parameters are valid. */
+ RTPTransmitter::TransmissionProtocol GetTransmissionProtocol() const { return protocol; }
+private:
+ RTPTransmitter::TransmissionProtocol protocol;
+};
+
+#endif // RTPTRANSMITTER_H
+
diff --git a/src/rtptypes.h b/src/rtptypes.h
new file mode 100644
index 0000000..e5377dd
--- /dev/null
+++ b/src/rtptypes.h
@@ -0,0 +1,37 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ #include "rtptypes_unix.h"
+#else
+ #include "rtptypes_win.h"
+#endif // WIN32
diff --git a/src/rtptypes_win.h b/src/rtptypes_win.h
new file mode 100644
index 0000000..66e20b2
--- /dev/null
+++ b/src/rtptypes_win.h
@@ -0,0 +1,62 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#ifndef RTPTYPES_H
+
+#define RTPTYPES_H
+
+#ifndef _WIN32_WCE
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+ #include <sys/types.h>
+#else
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+#endif // _WIN32_WCE
+
+#ifndef INTTYPES_DEFINED
+
+#define INTTYPES_DEFINED
+
+typedef char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef int int32_t;
+typedef unsigned int uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+#endif // INTTYPES_DEFINED
+
+#endif // RTPTYPES_H
+
diff --git a/src/rtpudpv4transmitter.cpp b/src/rtpudpv4transmitter.cpp
new file mode 100644
index 0000000..d421885
--- /dev/null
+++ b/src/rtpudpv4transmitter.cpp
@@ -0,0 +1,1925 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtpudpv4transmitter.h"
+#include "rtprawpacket.h"
+#include "rtpipv4address.h"
+#include "rtptimeutilities.h"
+#include "rtpdefines.h"
+#include <stdio.h>
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ #define RTPSOCKERR INVALID_SOCKET
+ #define RTPCLOSE(x) closesocket(x)
+ #define RTPSOCKLENTYPE int
+ #define RTPIOCTL ioctlsocket
+#else // not Win32
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <sys/ioctl.h>
+ #include <net/if.h>
+ #include <string.h>
+ #include <netdb.h>
+ #include <unistd.h>
+
+ #ifdef RTP_HAVE_SYS_FILIO
+ #include <sys/filio.h>
+ #endif // RTP_HAVE_SYS_FILIO
+ #ifdef RTP_HAVE_SYS_SOCKIO
+ #include <sys/sockio.h>
+ #endif // RTP_HAVE_SYS_SOCKIO
+ #ifdef RTP_SUPPORT_IFADDRS
+ #include <ifaddrs.h>
+ #endif // RTP_SUPPORT_IFADDRS
+
+ #define RTPSOCKERR -1
+ #define RTPCLOSE(x) close(x)
+
+ #ifdef RTP_SOCKLENTYPE_UINT
+ #define RTPSOCKLENTYPE unsigned int
+ #else
+ #define RTPSOCKLENTYPE int
+ #endif // RTP_SOCKLENTYPE_UINT
+
+ #define RTPIOCTL ioctl
+#endif // WIN32
+#ifdef RTPDEBUG
+ #include <iostream>
+#endif // RTPDEBUG
+
+#include "rtpdebug.h"
+
+#include <iostream>
+
+#define RTPUDPV4TRANS_MAXPACKSIZE 65535
+#define RTPUDPV4TRANS_IFREQBUFSIZE 8192
+
+#define RTPUDPV4TRANS_IS_MCASTADDR(x) (((x)&0xF0000000) == 0xE0000000)
+
+#define RTPUDPV4TRANS_MCASTMEMBERSHIP(socket,type,mcastip,status) {\
+ struct ip_mreq mreq;\
+ \
+ mreq.imr_multiaddr.s_addr = htonl(mcastip);\
+ mreq.imr_interface.s_addr = htonl(mcastifaceIP);\
+ status = setsockopt(socket,IPPROTO_IP,type,(const char *)&mreq,sizeof(struct ip_mreq));\
+ }
+#ifdef RTP_SUPPORT_THREAD
+ #define MAINMUTEX_LOCK { if (threadsafe) mainmutex.Lock(); }
+ #define MAINMUTEX_UNLOCK { if (threadsafe) mainmutex.Unlock(); }
+ #define WAITMUTEX_LOCK { if (threadsafe) waitmutex.Lock(); }
+ #define WAITMUTEX_UNLOCK { if (threadsafe) waitmutex.Unlock(); }
+#else
+ #define MAINMUTEX_LOCK
+ #define MAINMUTEX_UNLOCK
+ #define WAITMUTEX_LOCK
+ #define WAITMUTEX_UNLOCK
+#endif // RTP_SUPPORT_THREAD
+
+RTPUDPv4Transmitter::RTPUDPv4Transmitter(RTPMemoryManager *mgr) : RTPTransmitter(mgr),destinations(mgr,RTPMEM_TYPE_CLASS_DESTINATIONLISTHASHELEMENT),multicastgroups(mgr,RTPMEM_TYPE_CLASS_MULTICASTHASHELEMENT),
+ acceptignoreinfo(mgr,RTPMEM_TYPE_CLASS_ACCEPTIGNOREHASHELEMENT)
+{
+ created = false;
+ init = false;
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ timeinit.Dummy();
+#endif // WIN32 || _WIN32_WCE
+}
+
+RTPUDPv4Transmitter::~RTPUDPv4Transmitter()
+{
+ Destroy();
+}
+
+int RTPUDPv4Transmitter::Init(bool tsafe)
+{
+ if (init)
+ return ERR_RTP_UDPV4TRANS_ALREADYINIT;
+
+#ifdef RTP_SUPPORT_THREAD
+ threadsafe = tsafe;
+ if (threadsafe)
+ {
+ int status;
+
+ status = mainmutex.Init();
+ if (status < 0)
+ return ERR_RTP_UDPV4TRANS_CANTINITMUTEX;
+ status = waitmutex.Init();
+ if (status < 0)
+ return ERR_RTP_UDPV4TRANS_CANTINITMUTEX;
+ }
+#else
+ if (tsafe)
+ return ERR_RTP_NOTHREADSUPPORT;
+#endif // RTP_SUPPORT_THREAD
+
+ init = true;
+ return 0;
+}
+
+int RTPUDPv4Transmitter::Create(size_t maximumpacketsize,const RTPTransmissionParams *transparams)
+{
+ const RTPUDPv4TransmissionParams *params,defaultparams;
+ struct sockaddr_in addr;
+ RTPSOCKLENTYPE size;
+ int status;
+
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_ALREADYCREATED;
+ }
+
+ // Obtain transmission parameters
+
+ if (transparams == 0)
+ params = &defaultparams;
+ else
+ {
+ if (transparams->GetTransmissionProtocol() != RTPTransmitter::IPv4UDPProto)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_ILLEGALPARAMETERS;
+ }
+ params = (const RTPUDPv4TransmissionParams *)transparams;
+ }
+
+ // Check if portbase is even
+ if (params->GetPortbase()%2 != 0)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_PORTBASENOTEVEN;
+ }
+
+ // create sockets
+
+ rtpsock = socket(PF_INET,SOCK_DGRAM,0);
+ if (rtpsock == RTPSOCKERR)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_CANTCREATESOCKET;
+ }
+ rtcpsock = socket(PF_INET,SOCK_DGRAM,0);
+ if (rtcpsock == RTPSOCKERR)
+ {
+ RTPCLOSE(rtpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_CANTCREATESOCKET;
+ }
+
+ // set socket buffer sizes
+
+ size = params->GetRTPReceiveBuffer();
+ if (setsockopt(rtpsock,SOL_SOCKET,SO_RCVBUF,(const char *)&size,sizeof(int)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_CANTSETRTPRECEIVEBUF;
+ }
+ size = params->GetRTPSendBuffer();
+ if (setsockopt(rtpsock,SOL_SOCKET,SO_SNDBUF,(const char *)&size,sizeof(int)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_CANTSETRTPTRANSMITBUF;
+ }
+ size = params->GetRTCPReceiveBuffer();
+ if (setsockopt(rtcpsock,SOL_SOCKET,SO_RCVBUF,(const char *)&size,sizeof(int)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_CANTSETRTCPRECEIVEBUF;
+ }
+ size = params->GetRTCPSendBuffer();
+ if (setsockopt(rtcpsock,SOL_SOCKET,SO_SNDBUF,(const char *)&size,sizeof(int)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_CANTSETRTCPTRANSMITBUF;
+ }
+
+ // bind sockets
+
+ bindIP = params->GetBindIP();
+ mcastifaceIP = params->GetMulticastInterfaceIP();
+
+ memset(&addr,0,sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(params->GetPortbase());
+ addr.sin_addr.s_addr = htonl(bindIP);
+ if (bind(rtpsock,(struct sockaddr *)&addr,sizeof(struct sockaddr_in)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_CANTBINDRTPSOCKET;
+ }
+ memset(&addr,0,sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(params->GetPortbase()+1);
+ addr.sin_addr.s_addr = htonl(bindIP);
+ if (bind(rtcpsock,(struct sockaddr *)&addr,sizeof(struct sockaddr_in)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_CANTBINDRTCPSOCKET;
+ }
+
+ // Try to obtain local IP addresses
+
+ localIPs = params->GetLocalIPList();
+ if (localIPs.empty()) // User did not provide list of local IP addresses, calculate them
+ {
+ int status;
+
+ if ((status = CreateLocalIPList()) < 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return status;
+ }
+#ifdef RTPDEBUG
+ std::cout << "Found these local IP addresses:" << std::endl;
+
+ std::list<uint32_t>::const_iterator it;
+
+ for (it = localIPs.begin() ; it != localIPs.end() ; it++)
+ {
+ RTPIPv4Address a(*it);
+
+ std::cout << a.GetAddressString() << std::endl;
+ }
+#endif // RTPDEBUG
+ }
+
+#ifdef RTP_SUPPORT_IPV4MULTICAST
+ if (SetMulticastTTL(params->GetMulticastTTL()))
+ supportsmulticasting = true;
+ else
+ supportsmulticasting = false;
+#else // no multicast support enabled
+ supportsmulticasting = false;
+#endif // RTP_SUPPORT_IPV4MULTICAST
+
+ if ((status = CreateAbortDescriptors()) < 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return status;
+ }
+
+ if (maximumpacketsize > RTPUDPV4TRANS_MAXPACKSIZE)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ DestroyAbortDescriptors();
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_SPECIFIEDSIZETOOBIG;
+ }
+
+ maxpacksize = maximumpacketsize;
+ portbase = params->GetPortbase();
+ multicastTTL = params->GetMulticastTTL();
+ receivemode = RTPTransmitter::AcceptAll;
+
+ localhostname = 0;
+ localhostnamelength = 0;
+
+ waitingfordata = false;
+ created = true;
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+void RTPUDPv4Transmitter::Destroy()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK;
+ return;
+ }
+
+ if (localhostname)
+ {
+ RTPDeleteByteArray(localhostname,GetMemoryManager());
+ localhostname = 0;
+ localhostnamelength = 0;
+ }
+
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ destinations.Clear();
+#ifdef RTP_SUPPORT_IPV4MULTICAST
+ multicastgroups.Clear();
+#endif // RTP_SUPPORT_IPV4MULTICAST
+ FlushPackets();
+ ClearAcceptIgnoreInfo();
+ localIPs.clear();
+ created = false;
+
+ if (waitingfordata)
+ {
+ AbortWaitInternal();
+ DestroyAbortDescriptors();
+ MAINMUTEX_UNLOCK
+ WAITMUTEX_LOCK // to make sure that the WaitForIncomingData function ended
+ WAITMUTEX_UNLOCK
+ }
+ else
+ DestroyAbortDescriptors();
+
+ MAINMUTEX_UNLOCK
+}
+
+RTPTransmissionInfo *RTPUDPv4Transmitter::GetTransmissionInfo()
+{
+ if (!init)
+ return 0;
+
+ MAINMUTEX_LOCK
+ RTPTransmissionInfo *tinf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPTRANSMISSIONINFO) RTPUDPv4TransmissionInfo(localIPs,rtpsock,rtcpsock);
+ MAINMUTEX_UNLOCK
+ return tinf;
+}
+
+int RTPUDPv4Transmitter::GetLocalHostName(uint8_t *buffer,size_t *bufferlength)
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+
+ if (localhostname == 0)
+ {
+ if (localIPs.empty())
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOLOCALIPS;
+ }
+
+ std::list<uint32_t>::const_iterator it;
+ std::list<std::string> hostnames;
+
+ for (it = localIPs.begin() ; it != localIPs.end() ; it++)
+ {
+ bool founddouble = false;
+ bool foundentry = true;
+
+ while (!founddouble && foundentry)
+ {
+ struct hostent *he;
+ uint8_t addr[4];
+ uint32_t ip = (*it);
+
+ addr[0] = (uint8_t)((ip>>24)&0xFF);
+ addr[1] = (uint8_t)((ip>>16)&0xFF);
+ addr[2] = (uint8_t)((ip>>8)&0xFF);
+ addr[3] = (uint8_t)(ip&0xFF);
+ he = gethostbyaddr((char *)addr,4,AF_INET);
+ if (he != 0)
+ {
+ std::string hname = std::string(he->h_name);
+ std::list<std::string>::const_iterator it;
+
+ for (it = hostnames.begin() ; !founddouble && it != hostnames.end() ; it++)
+ if ((*it) == hname)
+ founddouble = true;
+
+ if (!founddouble)
+ hostnames.push_back(hname);
+
+ int i = 0;
+ while (!founddouble && he->h_aliases[i] != 0)
+ {
+ std::string hname = std::string(he->h_aliases[i]);
+
+ for (it = hostnames.begin() ; !founddouble && it != hostnames.end() ; it++)
+ if ((*it) == hname)
+ founddouble = true;
+
+ if (!founddouble)
+ {
+ hostnames.push_back(hname);
+ i++;
+ }
+ }
+ }
+ else
+ foundentry = false;
+ }
+ }
+
+ bool found = false;
+
+ if (!hostnames.empty()) // try to select the most appropriate hostname
+ {
+ std::list<std::string>::const_iterator it;
+
+ hostnames.sort();
+ for (it = hostnames.begin() ; !found && it != hostnames.end() ; it++)
+ {
+ if ((*it).find('.') != std::string::npos)
+ {
+ found = true;
+ localhostnamelength = (*it).length();
+ localhostname = RTPNew(GetMemoryManager(),RTPMEM_TYPE_OTHER) uint8_t [localhostnamelength+1];
+ if (localhostname == 0)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_OUTOFMEM;
+ }
+ memcpy(localhostname,(*it).c_str(),localhostnamelength);
+ localhostname[localhostnamelength] = 0;
+ }
+ }
+ }
+
+ if (!found) // use an IP address
+ {
+ uint32_t ip;
+ int len;
+ char str[16];
+
+ it = localIPs.begin();
+ ip = (*it);
+
+ RTP_SNPRINTF(str,16,"%d.%d.%d.%d",(int)((ip>>24)&0xFF),(int)((ip>>16)&0xFF),(int)((ip>>8)&0xFF),(int)(ip&0xFF));
+ len = strlen(str);
+
+ localhostnamelength = len;
+ localhostname = RTPNew(GetMemoryManager(),RTPMEM_TYPE_OTHER) uint8_t [localhostnamelength + 1];
+ if (localhostname == 0)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_OUTOFMEM;
+ }
+ memcpy(localhostname,str,localhostnamelength);
+ localhostname[localhostnamelength] = 0;
+ }
+ }
+
+ if ((*bufferlength) < localhostnamelength)
+ {
+ *bufferlength = localhostnamelength; // tell the application the required size of the buffer
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_TRANS_BUFFERLENGTHTOOSMALL;
+ }
+
+ memcpy(buffer,localhostname,localhostnamelength);
+ *bufferlength = localhostnamelength;
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+bool RTPUDPv4Transmitter::ComesFromThisTransmitter(const RTPAddress *addr)
+{
+ if (!init)
+ return false;
+
+ if (addr == 0)
+ return false;
+
+ MAINMUTEX_LOCK
+
+ bool v;
+
+ if (created && addr->GetAddressType() == RTPAddress::IPv4Address)
+ {
+ const RTPIPv4Address *addr2 = (const RTPIPv4Address *)addr;
+ bool found = false;
+ std::list<uint32_t>::const_iterator it;
+
+ it = localIPs.begin();
+ while (!found && it != localIPs.end())
+ {
+ if (addr2->GetIP() == *it)
+ found = true;
+ else
+ ++it;
+ }
+
+ if (!found)
+ v = false;
+ else
+ {
+ if (addr2->GetPort() == portbase) // check for RTP port
+ v = true;
+ else if (addr2->GetPort() == (portbase+1)) // check for RTCP port
+ v = true;
+ else
+ v = false;
+ }
+ }
+ else
+ v = false;
+
+ MAINMUTEX_UNLOCK
+ return v;
+}
+
+int RTPUDPv4Transmitter::Poll()
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ int status;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+ status = PollSocket(true); // poll RTP socket
+ if (status >= 0)
+ status = PollSocket(false); // poll RTCP socket
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPUDPv4Transmitter::WaitForIncomingData(const RTPTime &delay,bool *dataavailable)
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ fd_set fdset;
+ struct timeval tv;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+ if (waitingfordata)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_ALREADYWAITING;
+ }
+
+ FD_ZERO(&fdset);
+ FD_SET(rtpsock,&fdset);
+ FD_SET(rtcpsock,&fdset);
+ FD_SET(abortdesc[0],&fdset);
+ tv.tv_sec = delay.GetSeconds();
+ tv.tv_usec = delay.GetMicroSeconds();
+
+ waitingfordata = true;
+
+ WAITMUTEX_LOCK
+ MAINMUTEX_UNLOCK
+
+ if (select(FD_SETSIZE,&fdset,0,0,&tv) < 0)
+ {
+ MAINMUTEX_LOCK
+ waitingfordata = false;
+ MAINMUTEX_UNLOCK
+ WAITMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_ERRORINSELECT;
+ }
+
+ MAINMUTEX_LOCK
+ waitingfordata = false;
+ if (!created) // destroy called
+ {
+ MAINMUTEX_UNLOCK;
+ WAITMUTEX_UNLOCK
+ return 0;
+ }
+
+ // if aborted, read from abort buffer
+ if (FD_ISSET(abortdesc[0],&fdset))
+ {
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ char buf[1];
+
+ recv(abortdesc[0],buf,1,0);
+#else
+ unsigned char buf[1];
+
+ read(abortdesc[0],buf,1);
+#endif // WIN32
+ }
+
+ if (dataavailable != 0)
+ {
+ if (FD_ISSET(rtpsock,&fdset) || FD_ISSET(rtcpsock,&fdset))
+ *dataavailable = true;
+ else
+ *dataavailable = false;
+ }
+
+ MAINMUTEX_UNLOCK
+ WAITMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPUDPv4Transmitter::AbortWait()
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+ if (!waitingfordata)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTWAITING;
+ }
+
+ AbortWaitInternal();
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPUDPv4Transmitter::SendRTPData(const void *data,size_t len)
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+ if (len > maxpacksize)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_SPECIFIEDSIZETOOBIG;
+ }
+
+ destinations.GotoFirstElement();
+ while (destinations.HasCurrentElement())
+ {
+ sendto(rtpsock,(const char *)data,len,0,(const struct sockaddr *)destinations.GetCurrentElement().GetRTPSockAddr(),sizeof(struct sockaddr_in));
+ destinations.GotoNextElement();
+ }
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPUDPv4Transmitter::SendRTCPData(const void *data,size_t len)
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+ if (len > maxpacksize)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_SPECIFIEDSIZETOOBIG;
+ }
+
+ destinations.GotoFirstElement();
+ while (destinations.HasCurrentElement())
+ {
+ sendto(rtcpsock,(const char *)data,len,0,(const struct sockaddr *)destinations.GetCurrentElement().GetRTCPSockAddr(),sizeof(struct sockaddr_in));
+ destinations.GotoNextElement();
+ }
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPUDPv4Transmitter::AddDestination(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_INVALIDADDRESSTYPE;
+ }
+
+ RTPIPv4Address &address = (RTPIPv4Address &)addr;
+ RTPIPv4Destination dest(address.GetIP(),address.GetPort());
+ int status = destinations.AddElement(dest);
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPUDPv4Transmitter::DeleteDestination(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_INVALIDADDRESSTYPE;
+ }
+
+ RTPIPv4Address &address = (RTPIPv4Address &)addr;
+ RTPIPv4Destination dest(address.GetIP(),address.GetPort());
+ int status = destinations.DeleteElement(dest);
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+void RTPUDPv4Transmitter::ClearDestinations()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created)
+ destinations.Clear();
+ MAINMUTEX_UNLOCK
+}
+
+bool RTPUDPv4Transmitter::SupportsMulticasting()
+{
+ if (!init)
+ return false;
+
+ MAINMUTEX_LOCK
+
+ bool v;
+
+ if (!created)
+ v = false;
+ else
+ v = supportsmulticasting;
+
+ MAINMUTEX_UNLOCK
+ return v;
+}
+
+#ifdef RTP_SUPPORT_IPV4MULTICAST
+
+int RTPUDPv4Transmitter::JoinMulticastGroup(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_INVALIDADDRESSTYPE;
+ }
+
+ const RTPIPv4Address &address = (const RTPIPv4Address &)addr;
+ uint32_t mcastIP = address.GetIP();
+
+ if (!RTPUDPV4TRANS_IS_MCASTADDR(mcastIP))
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTAMULTICASTADDRESS;
+ }
+
+ status = multicastgroups.AddElement(mcastIP);
+ if (status >= 0)
+ {
+ RTPUDPV4TRANS_MCASTMEMBERSHIP(rtpsock,IP_ADD_MEMBERSHIP,mcastIP,status);
+ if (status != 0)
+ {
+ multicastgroups.DeleteElement(mcastIP);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_COULDNTJOINMULTICASTGROUP;
+ }
+ RTPUDPV4TRANS_MCASTMEMBERSHIP(rtcpsock,IP_ADD_MEMBERSHIP,mcastIP,status);
+ if (status != 0)
+ {
+ RTPUDPV4TRANS_MCASTMEMBERSHIP(rtpsock,IP_DROP_MEMBERSHIP,mcastIP,status);
+ multicastgroups.DeleteElement(mcastIP);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_COULDNTJOINMULTICASTGROUP;
+ }
+ }
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPUDPv4Transmitter::LeaveMulticastGroup(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_INVALIDADDRESSTYPE;
+ }
+
+ const RTPIPv4Address &address = (const RTPIPv4Address &)addr;
+ uint32_t mcastIP = address.GetIP();
+
+ if (!RTPUDPV4TRANS_IS_MCASTADDR(mcastIP))
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTAMULTICASTADDRESS;
+ }
+
+ status = multicastgroups.DeleteElement(mcastIP);
+ if (status >= 0)
+ {
+ RTPUDPV4TRANS_MCASTMEMBERSHIP(rtpsock,IP_DROP_MEMBERSHIP,mcastIP,status);
+ RTPUDPV4TRANS_MCASTMEMBERSHIP(rtcpsock,IP_DROP_MEMBERSHIP,mcastIP,status);
+ status = 0;
+ }
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+void RTPUDPv4Transmitter::LeaveAllMulticastGroups()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created)
+ {
+ multicastgroups.GotoFirstElement();
+ while (multicastgroups.HasCurrentElement())
+ {
+ uint32_t mcastIP;
+ int status = 0;
+
+ mcastIP = multicastgroups.GetCurrentElement();
+ RTPUDPV4TRANS_MCASTMEMBERSHIP(rtpsock,IP_DROP_MEMBERSHIP,mcastIP,status);
+ RTPUDPV4TRANS_MCASTMEMBERSHIP(rtcpsock,IP_DROP_MEMBERSHIP,mcastIP,status);
+ multicastgroups.GotoNextElement();
+ }
+ multicastgroups.Clear();
+ }
+ MAINMUTEX_UNLOCK
+}
+
+#else // no multicast support
+
+int RTPUDPv4Transmitter::JoinMulticastGroup(const RTPAddress &addr)
+{
+ return ERR_RTP_UDPV4TRANS_NOMULTICASTSUPPORT;
+}
+
+int RTPUDPv4Transmitter::LeaveMulticastGroup(const RTPAddress &addr)
+{
+ return ERR_RTP_UDPV4TRANS_NOMULTICASTSUPPORT;
+}
+
+void RTPUDPv4Transmitter::LeaveAllMulticastGroups()
+{
+}
+
+#endif // RTP_SUPPORT_IPV4MULTICAST
+
+int RTPUDPv4Transmitter::SetReceiveMode(RTPTransmitter::ReceiveMode m)
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+ if (m != receivemode)
+ {
+ receivemode = m;
+ acceptignoreinfo.Clear();
+ }
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPUDPv4Transmitter::AddToIgnoreList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::IgnoreSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv4Address &address = (const RTPIPv4Address &)addr;
+ status = ProcessAddAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPUDPv4Transmitter::DeleteFromIgnoreList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::IgnoreSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv4Address &address = (const RTPIPv4Address &)addr;
+ status = ProcessDeleteAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+void RTPUDPv4Transmitter::ClearIgnoreList()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created && receivemode == RTPTransmitter::IgnoreSome)
+ ClearAcceptIgnoreInfo();
+ MAINMUTEX_UNLOCK
+}
+
+int RTPUDPv4Transmitter::AddToAcceptList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::AcceptSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv4Address &address = (const RTPIPv4Address &)addr;
+ status = ProcessAddAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPUDPv4Transmitter::DeleteFromAcceptList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv4Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::AcceptSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv4Address &address = (const RTPIPv4Address &)addr;
+ status = ProcessDeleteAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+void RTPUDPv4Transmitter::ClearAcceptList()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created && receivemode == RTPTransmitter::AcceptSome)
+ ClearAcceptIgnoreInfo();
+ MAINMUTEX_UNLOCK
+}
+
+int RTPUDPv4Transmitter::SetMaximumPacketSize(size_t s)
+{
+ if (!init)
+ return ERR_RTP_UDPV4TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_NOTCREATED;
+ }
+ if (s > RTPUDPV4TRANS_MAXPACKSIZE)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV4TRANS_SPECIFIEDSIZETOOBIG;
+ }
+ maxpacksize = s;
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+bool RTPUDPv4Transmitter::NewDataAvailable()
+{
+ if (!init)
+ return false;
+
+ MAINMUTEX_LOCK
+
+ bool v;
+
+ if (!created)
+ v = false;
+ else
+ {
+ if (rawpacketlist.empty())
+ v = false;
+ else
+ v = true;
+ }
+
+ MAINMUTEX_UNLOCK
+ return v;
+}
+
+RTPRawPacket *RTPUDPv4Transmitter::GetNextPacket()
+{
+ if (!init)
+ return 0;
+
+ MAINMUTEX_LOCK
+
+ RTPRawPacket *p;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return 0;
+ }
+ if (rawpacketlist.empty())
+ {
+ MAINMUTEX_UNLOCK
+ return 0;
+ }
+
+ p = *(rawpacketlist.begin());
+ rawpacketlist.pop_front();
+
+ MAINMUTEX_UNLOCK
+ return p;
+}
+
+// Here the private functions start...
+
+#ifdef RTP_SUPPORT_IPV4MULTICAST
+bool RTPUDPv4Transmitter::SetMulticastTTL(uint8_t ttl)
+{
+ int ttl2,status;
+
+ ttl2 = (int)ttl;
+ status = setsockopt(rtpsock,IPPROTO_IP,IP_MULTICAST_TTL,(const char *)&ttl2,sizeof(int));
+ if (status != 0)
+ return false;
+ status = setsockopt(rtcpsock,IPPROTO_IP,IP_MULTICAST_TTL,(const char *)&ttl2,sizeof(int));
+ if (status != 0)
+ return false;
+ return true;
+}
+#endif // RTP_SUPPORT_IPV4MULTICAST
+
+void RTPUDPv4Transmitter::FlushPackets()
+{
+ std::list<RTPRawPacket*>::const_iterator it;
+
+ for (it = rawpacketlist.begin() ; it != rawpacketlist.end() ; ++it)
+ RTPDelete(*it,GetMemoryManager());
+ rawpacketlist.clear();
+}
+
+int RTPUDPv4Transmitter::PollSocket(bool rtp)
+{
+ RTPSOCKLENTYPE fromlen;
+ int recvlen;
+ char packetbuffer[RTPUDPV4TRANS_MAXPACKSIZE];
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ SOCKET sock;
+ unsigned long len;
+#else
+ size_t len;
+ int sock;
+#endif // WIN32
+ struct sockaddr_in srcaddr;
+
+ if (rtp)
+ sock = rtpsock;
+ else
+ sock = rtcpsock;
+
+ len = 0;
+ RTPIOCTL(sock,FIONREAD,&len);
+ if (len <= 0)
+ return 0;
+
+ while (len > 0)
+ {
+ RTPTime curtime = RTPTime::CurrentTime();
+ fromlen = sizeof(struct sockaddr_in);
+ recvlen = recvfrom(sock,packetbuffer,RTPUDPV4TRANS_MAXPACKSIZE,0,(struct sockaddr *)&srcaddr,&fromlen);
+ if (recvlen > 0)
+ {
+ bool acceptdata;
+
+ // got data, process it
+ if (receivemode == RTPTransmitter::AcceptAll)
+ acceptdata = true;
+ else
+ acceptdata = ShouldAcceptData(ntohl(srcaddr.sin_addr.s_addr),ntohs(srcaddr.sin_port));
+
+ if (acceptdata)
+ {
+ RTPRawPacket *pack;
+ RTPIPv4Address *addr;
+ uint8_t *datacopy;
+
+ addr = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPADDRESS) RTPIPv4Address(ntohl(srcaddr.sin_addr.s_addr),ntohs(srcaddr.sin_port));
+ if (addr == 0)
+ return ERR_RTP_OUTOFMEM;
+ datacopy = RTPNew(GetMemoryManager(),(rtp)?RTPMEM_TYPE_BUFFER_RECEIVEDRTPPACKET:RTPMEM_TYPE_BUFFER_RECEIVEDRTCPPACKET) uint8_t[recvlen];
+ if (datacopy == 0)
+ {
+ RTPDelete(addr,GetMemoryManager());
+ return ERR_RTP_OUTOFMEM;
+ }
+ memcpy(datacopy,packetbuffer,recvlen);
+
+ pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET) RTPRawPacket(datacopy,recvlen,addr,curtime,rtp,GetMemoryManager());
+ if (pack == 0)
+ {
+ RTPDelete(addr,GetMemoryManager());
+ RTPDeleteByteArray(datacopy,GetMemoryManager());
+ return ERR_RTP_OUTOFMEM;
+ }
+ rawpacketlist.push_back(pack);
+ }
+ }
+ len = 0;
+ RTPIOCTL(sock,FIONREAD,&len);
+ }
+ return 0;
+}
+
+int RTPUDPv4Transmitter::ProcessAddAcceptIgnoreEntry(uint32_t ip,uint16_t port)
+{
+ acceptignoreinfo.GotoElement(ip);
+ if (acceptignoreinfo.HasCurrentElement()) // An entry for this IP address already exists
+ {
+ PortInfo *portinf = acceptignoreinfo.GetCurrentElement();
+
+ if (port == 0) // select all ports
+ {
+ portinf->all = true;
+ portinf->portlist.clear();
+ }
+ else if (!portinf->all)
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = portinf->portlist.begin();
+ end = portinf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == port) // already in list
+ return 0;
+ }
+ portinf->portlist.push_front(port);
+ }
+ }
+ else // got to create an entry for this IP address
+ {
+ PortInfo *portinf;
+ int status;
+
+ portinf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_ACCEPTIGNOREPORTINFO) PortInfo();
+ if (port == 0) // select all ports
+ portinf->all = true;
+ else
+ portinf->portlist.push_front(port);
+
+ status = acceptignoreinfo.AddElement(ip,portinf);
+ if (status < 0)
+ {
+ RTPDelete(portinf,GetMemoryManager());
+ return status;
+ }
+ }
+
+ return 0;
+}
+
+void RTPUDPv4Transmitter::ClearAcceptIgnoreInfo()
+{
+ acceptignoreinfo.GotoFirstElement();
+ while (acceptignoreinfo.HasCurrentElement())
+ {
+ PortInfo *inf;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ RTPDelete(inf,GetMemoryManager());
+ acceptignoreinfo.GotoNextElement();
+ }
+ acceptignoreinfo.Clear();
+}
+
+int RTPUDPv4Transmitter::ProcessDeleteAcceptIgnoreEntry(uint32_t ip,uint16_t port)
+{
+ acceptignoreinfo.GotoElement(ip);
+ if (!acceptignoreinfo.HasCurrentElement())
+ return ERR_RTP_UDPV4TRANS_NOSUCHENTRY;
+
+ PortInfo *inf;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ if (port == 0) // delete all entries
+ {
+ inf->all = false;
+ inf->portlist.clear();
+ }
+ else // a specific port was selected
+ {
+ if (inf->all) // currently, all ports are selected. Add the one to remove to the list
+ {
+ // we have to check if the list doesn't contain the port already
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == port) // already in list: this means we already deleted the entry
+ return ERR_RTP_UDPV4TRANS_NOSUCHENTRY;
+ }
+ inf->portlist.push_front(port);
+ }
+ else // check if we can find the port in the list
+ {
+ std::list<uint16_t>::iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; ++it)
+ {
+ if (*it == port) // found it!
+ {
+ inf->portlist.erase(it);
+ return 0;
+ }
+ }
+ // didn't find it
+ return ERR_RTP_UDPV4TRANS_NOSUCHENTRY;
+ }
+ }
+ return 0;
+}
+
+bool RTPUDPv4Transmitter::ShouldAcceptData(uint32_t srcip,uint16_t srcport)
+{
+ if (receivemode == RTPTransmitter::AcceptSome)
+ {
+ PortInfo *inf;
+
+ acceptignoreinfo.GotoElement(srcip);
+ if (!acceptignoreinfo.HasCurrentElement())
+ return false;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ if (!inf->all) // only accept the ones in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return true;
+ }
+ return false;
+ }
+ else // accept all, except the ones in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return false;
+ }
+ return true;
+ }
+ }
+ else // IgnoreSome
+ {
+ PortInfo *inf;
+
+ acceptignoreinfo.GotoElement(srcip);
+ if (!acceptignoreinfo.HasCurrentElement())
+ return true;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ if (!inf->all) // ignore the ports in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return false;
+ }
+ return true;
+ }
+ else // ignore all, except the ones in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return true;
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
+#if (defined(WIN32) || defined(_WIN32_WCE))
+
+int RTPUDPv4Transmitter::CreateAbortDescriptors()
+{
+ SOCKET listensock;
+ int size;
+ struct sockaddr_in addr;
+
+ listensock = socket(PF_INET,SOCK_STREAM,0);
+ if (listensock == RTPSOCKERR)
+ return ERR_RTP_UDPV4TRANS_CANTCREATEABORTDESCRIPTORS;
+
+ memset(&addr,0,sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ if (bind(listensock,(struct sockaddr *)&addr,sizeof(struct sockaddr_in)) != 0)
+ {
+ RTPCLOSE(listensock);
+ return ERR_RTP_UDPV4TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in));
+ size = sizeof(struct sockaddr_in);
+ if (getsockname(listensock,(struct sockaddr*)&addr,&size) != 0)
+ {
+ RTPCLOSE(listensock);
+ return ERR_RTP_UDPV4TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ unsigned short connectport = ntohs(addr.sin_port);
+
+ abortdesc[0] = socket(PF_INET,SOCK_STREAM,0);
+ if (abortdesc[0] == RTPSOCKERR)
+ {
+ RTPCLOSE(listensock);
+ return ERR_RTP_UDPV4TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ if (bind(abortdesc[0],(struct sockaddr *)&addr,sizeof(struct sockaddr_in)) != 0)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_UDPV4TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ if (listen(listensock,1) != 0)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_UDPV4TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ addr.sin_port = htons(connectport);
+
+ if (connect(abortdesc[0],(struct sockaddr *)&addr,sizeof(struct sockaddr_in)) != 0)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_UDPV4TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in));
+ size = sizeof(struct sockaddr_in);
+ abortdesc[1] = accept(listensock,(struct sockaddr *)&addr,&size);
+ if (abortdesc[1] == RTPSOCKERR)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_UDPV4TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ // okay, got the connection, close the listening socket
+
+ RTPCLOSE(listensock);
+ return 0;
+}
+
+void RTPUDPv4Transmitter::DestroyAbortDescriptors()
+{
+ RTPCLOSE(abortdesc[0]);
+ RTPCLOSE(abortdesc[1]);
+}
+
+#else // in a non winsock environment we can use pipes
+
+int RTPUDPv4Transmitter::CreateAbortDescriptors()
+{
+ if (pipe(abortdesc) < 0)
+ return ERR_RTP_UDPV4TRANS_CANTCREATEPIPE;
+ return 0;
+}
+
+void RTPUDPv4Transmitter::DestroyAbortDescriptors()
+{
+ close(abortdesc[0]);
+ close(abortdesc[1]);
+}
+
+#endif // WIN32
+
+int RTPUDPv4Transmitter::CreateLocalIPList()
+{
+ // first try to obtain the list from the network interface info
+
+ if (!GetLocalIPList_Interfaces())
+ {
+ // If this fails, we'll have to depend on DNS info
+ GetLocalIPList_DNS();
+ }
+ AddLoopbackAddress();
+ return 0;
+}
+
+#if (defined(WIN32) || defined(_WIN32_WCE))
+
+bool RTPUDPv4Transmitter::GetLocalIPList_Interfaces()
+{
+ unsigned char buffer[RTPUDPV4TRANS_IFREQBUFSIZE];
+ DWORD outputsize;
+ DWORD numaddresses,i;
+ SOCKET_ADDRESS_LIST *addrlist;
+
+ if (WSAIoctl(rtpsock,SIO_ADDRESS_LIST_QUERY,NULL,0,&buffer,RTPUDPV4TRANS_IFREQBUFSIZE,&outputsize,NULL,NULL))
+ return false;
+
+ addrlist = (SOCKET_ADDRESS_LIST *)buffer;
+ numaddresses = addrlist->iAddressCount;
+ for (i = 0 ; i < numaddresses ; i++)
+ {
+ SOCKET_ADDRESS *sockaddr = &(addrlist->Address[i]);
+ if (sockaddr->iSockaddrLength == sizeof(struct sockaddr_in)) // IPv4 address
+ {
+ struct sockaddr_in *addr = (struct sockaddr_in *)sockaddr->lpSockaddr;
+
+ localIPs.push_back(ntohl(addr->sin_addr.s_addr));
+ }
+ }
+
+ if (localIPs.empty())
+ return false;
+
+ return true;
+}
+
+#else // use either getifaddrs or ioctl
+
+#ifdef RTP_SUPPORT_IFADDRS
+
+bool RTPUDPv4Transmitter::GetLocalIPList_Interfaces()
+{
+ struct ifaddrs *addrs,*tmp;
+
+ getifaddrs(&addrs);
+ tmp = addrs;
+
+ while (tmp != 0)
+ {
+ if (tmp->ifa_addr != 0 && tmp->ifa_addr->sa_family == AF_INET)
+ {
+ struct sockaddr_in *inaddr = (struct sockaddr_in *)tmp->ifa_addr;
+ localIPs.push_back(ntohl(inaddr->sin_addr.s_addr));
+ }
+ tmp = tmp->ifa_next;
+ }
+
+ freeifaddrs(addrs);
+
+ if (localIPs.empty())
+ return false;
+ return true;
+}
+
+#else // user ioctl
+
+bool RTPUDPv4Transmitter::GetLocalIPList_Interfaces()
+{
+ int status;
+ char buffer[RTPUDPV4TRANS_IFREQBUFSIZE];
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ struct sockaddr *sa;
+ char *startptr,*endptr;
+ int remlen;
+
+ ifc.ifc_len = RTPUDPV4TRANS_IFREQBUFSIZE;
+ ifc.ifc_buf = buffer;
+ status = ioctl(rtpsock,SIOCGIFCONF,&ifc);
+ if (status < 0)
+ return false;
+
+ startptr = (char *)ifc.ifc_req;
+ endptr = startptr + ifc.ifc_len;
+ remlen = ifc.ifc_len;
+ while((startptr < endptr) && remlen >= (int)sizeof(struct ifreq))
+ {
+ ifr = (struct ifreq *)startptr;
+ sa = &(ifr->ifr_addr);
+#ifdef RTP_HAVE_SOCKADDR_LEN
+ if (sa->sa_len <= sizeof(struct sockaddr))
+ {
+ if (sa->sa_len == sizeof(struct sockaddr_in) && sa->sa_family == PF_INET)
+ {
+ uint32_t ip;
+ struct sockaddr_in *addr = (struct sockaddr_in *)sa;
+
+ ip = ntohl(addr->sin_addr.s_addr);
+ localIPs.push_back(ip);
+ }
+ remlen -= sizeof(struct ifreq);
+ startptr += sizeof(struct ifreq);
+ }
+ else
+ {
+ int l = sa->sa_len-sizeof(struct sockaddr)+sizeof(struct ifreq);
+
+ remlen -= l;
+ startptr += l;
+ }
+#else // don't have sa_len in struct sockaddr
+ if (sa->sa_family == PF_INET)
+ {
+ uint32_t ip;
+ struct sockaddr_in *addr = (struct sockaddr_in *)sa;
+
+ ip = ntohl(addr->sin_addr.s_addr);
+ localIPs.push_back(ip);
+ }
+ remlen -= sizeof(struct ifreq);
+ startptr += sizeof(struct ifreq);
+
+#endif // RTP_HAVE_SOCKADDR_LEN
+ }
+
+ if (localIPs.empty())
+ return false;
+ return true;
+}
+
+#endif // RTP_SUPPORT_IFADDRS
+
+#endif // WIN32
+
+void RTPUDPv4Transmitter::GetLocalIPList_DNS()
+{
+ struct hostent *he;
+ char name[1024];
+ uint32_t ip;
+ bool done;
+ int i,j;
+
+ gethostname(name,1023);
+ name[1023] = 0;
+ he = gethostbyname(name);
+ if (he == 0)
+ return;
+
+ ip = 0;
+ i = 0;
+ done = false;
+ while (!done)
+ {
+ if (he->h_addr_list[i] == NULL)
+ done = true;
+ else
+ {
+ ip = 0;
+ for (j = 0 ; j < 4 ; j++)
+ ip |= ((uint32_t)((unsigned char)he->h_addr_list[i][j])<<((3-j)*8));
+ localIPs.push_back(ip);
+ i++;
+ }
+ }
+}
+
+void RTPUDPv4Transmitter::AbortWaitInternal()
+{
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ send(abortdesc[1],"*",1,0);
+#else
+ write(abortdesc[1],"*",1);
+#endif // WIN32
+}
+
+void RTPUDPv4Transmitter::AddLoopbackAddress()
+{
+ uint32_t loopbackaddr = (((uint32_t)127)<<24)|((uint32_t)1);
+ std::list<uint32_t>::const_iterator it;
+ bool found = false;
+
+ for (it = localIPs.begin() ; !found && it != localIPs.end() ; it++)
+ {
+ if (*it == loopbackaddr)
+ found = true;
+ }
+
+ if (!found)
+ localIPs.push_back(loopbackaddr);
+}
+
+#ifdef RTPDEBUG
+void RTPUDPv4Transmitter::Dump()
+{
+ if (!init)
+ std::cout << "Not initialized" << std::endl;
+ else
+ {
+ MAINMUTEX_LOCK
+
+ if (!created)
+ std::cout << "Not created" << std::endl;
+ else
+ {
+ char str[16];
+ uint32_t ip;
+ std::list<uint32_t>::const_iterator it;
+
+ std::cout << "Portbase: " << portbase << std::endl;
+ std::cout << "RTP socket descriptor: " << rtpsock << std::endl;
+ std::cout << "RTCP socket descriptor: " << rtcpsock << std::endl;
+ ip = bindIP;
+ RTP_SNPRINTF(str,16,"%d.%d.%d.%d",(int)((ip>>24)&0xFF),(int)((ip>>16)&0xFF),(int)((ip>>8)&0xFF),(int)(ip&0xFF));
+ std::cout << "Bind IP address: " << str << std::endl;
+ ip = mcastifaceIP;
+ RTP_SNPRINTF(str,16,"%d.%d.%d.%d",(int)((ip>>24)&0xFF),(int)((ip>>16)&0xFF),(int)((ip>>8)&0xFF),(int)(ip&0xFF));
+ std::cout << "Multicast interface IP address: " << str << std::endl;
+ std::cout << "Local IP addresses:" << std::endl;
+ for (it = localIPs.begin() ; it != localIPs.end() ; it++)
+ {
+ ip = (*it);
+ RTP_SNPRINTF(str,16,"%d.%d.%d.%d",(int)((ip>>24)&0xFF),(int)((ip>>16)&0xFF),(int)((ip>>8)&0xFF),(int)(ip&0xFF));
+ std::cout << " " << str << std::endl;
+ }
+ std::cout << "Multicast TTL: " << (int)multicastTTL << std::endl;
+ std::cout << "Receive mode: ";
+ switch (receivemode)
+ {
+ case RTPTransmitter::AcceptAll:
+ std::cout << "Accept all";
+ break;
+ case RTPTransmitter::AcceptSome:
+ std::cout << "Accept some";
+ break;
+ case RTPTransmitter::IgnoreSome:
+ std::cout << "Ignore some";
+ }
+ std::cout << std::endl;
+ if (receivemode != RTPTransmitter::AcceptAll)
+ {
+ acceptignoreinfo.GotoFirstElement();
+ while(acceptignoreinfo.HasCurrentElement())
+ {
+ ip = acceptignoreinfo.GetCurrentKey();
+ RTP_SNPRINTF(str,16,"%d.%d.%d.%d",(int)((ip>>24)&0xFF),(int)((ip>>16)&0xFF),(int)((ip>>8)&0xFF),(int)(ip&0xFF));
+ PortInfo *pinfo = acceptignoreinfo.GetCurrentElement();
+ std::cout << " " << str << ": ";
+ if (pinfo->all)
+ {
+ std::cout << "All ports";
+ if (!pinfo->portlist.empty())
+ std::cout << ", except ";
+ }
+
+ std::list<uint16_t>::const_iterator it;
+
+ for (it = pinfo->portlist.begin() ; it != pinfo->portlist.end() ; )
+ {
+ std::cout << (*it);
+ it++;
+ if (it != pinfo->portlist.end())
+ std::cout << ", ";
+ }
+ std::cout << std::endl;
+ }
+ }
+
+ std::cout << "Local host name: ";
+ if (localhostname == 0)
+ std::cout << "Not set";
+ else
+ std::cout << localhostname;
+ std::cout << std::endl;
+
+ std::cout << "List of destinations: ";
+ destinations.GotoFirstElement();
+ if (destinations.HasCurrentElement())
+ {
+ std::cout << std::endl;
+ do
+ {
+ std::cout << " " << destinations.GetCurrentElement().GetDestinationString() << std::endl;
+ destinations.GotoNextElement();
+ } while (destinations.HasCurrentElement());
+ }
+ else
+ std::cout << "Empty" << std::endl;
+
+ std::cout << "Supports multicasting: " << ((supportsmulticasting)?"Yes":"No") << std::endl;
+#ifdef RTP_SUPPORT_IPV4MULTICAST
+ std::cout << "List of multicast groups: ";
+ multicastgroups.GotoFirstElement();
+ if (multicastgroups.HasCurrentElement())
+ {
+ std::cout << std::endl;
+ do
+ {
+ ip = multicastgroups.GetCurrentElement();
+ RTP_SNPRINTF(str,16,"%d.%d.%d.%d",(int)((ip>>24)&0xFF),(int)((ip>>16)&0xFF),(int)((ip>>8)&0xFF),(int)(ip&0xFF));
+ std::cout << " " << str << std::endl;
+ multicastgroups.GotoNextElement();
+ } while (multicastgroups.HasCurrentElement());
+ }
+ else
+ std::cout << "Empty" << std::endl;
+#endif // RTP_SUPPORT_IPV4MULTICAST
+
+ std::cout << "Number of raw packets in queue: " << rawpacketlist.size() << std::endl;
+ std::cout << "Maximum allowed packet size: " << maxpacksize << std::endl;
+ }
+
+ MAINMUTEX_UNLOCK
+ }
+}
+#endif // RTPDEBUG
+
diff --git a/src/rtpudpv4transmitter.h b/src/rtpudpv4transmitter.h
new file mode 100644
index 0000000..d96d6ea
--- /dev/null
+++ b/src/rtpudpv4transmitter.h
@@ -0,0 +1,302 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpudpv4transmitter.h
+ */
+
+#ifndef RTPUDPV4TRANSMITTER_H
+
+#define RTPUDPV4TRANSMITTER_H
+
+#include "rtpconfig.h"
+#include "rtptransmitter.h"
+#include "rtpipv4destination.h"
+#include "rtphashtable.h"
+#include "rtpkeyhashtable.h"
+#include <list>
+
+#ifdef RTP_SUPPORT_THREAD
+ #include <jmutex.h>
+#endif // RTP_SUPPORT_THREAD
+
+#define RTPUDPV4TRANS_HASHSIZE 8317
+#define RTPUDPV4TRANS_DEFAULTPORTBASE 5000
+
+#define RTPUDPV4TRANS_RTPRECEIVEBUFFER 32768
+#define RTPUDPV4TRANS_RTCPRECEIVEBUFFER 32768
+#define RTPUDPV4TRANS_RTPTRANSMITBUFFER 32768
+#define RTPUDPV4TRANS_RTCPTRANSMITBUFFER 32768
+
+/** Parameters for the UDP over IPv4 transmitter. */
+class RTPUDPv4TransmissionParams : public RTPTransmissionParams
+{
+public:
+ RTPUDPv4TransmissionParams():RTPTransmissionParams(RTPTransmitter::IPv4UDPProto) { portbase = RTPUDPV4TRANS_DEFAULTPORTBASE; bindIP = 0; multicastTTL = 1; mcastifaceIP = 0; rtpsendbuf = RTPUDPV4TRANS_RTPTRANSMITBUFFER; rtprecvbuf= RTPUDPV4TRANS_RTPRECEIVEBUFFER; rtcpsendbuf = RTPUDPV4TRANS_RTCPTRANSMITBUFFER; rtcprecvbuf = RTPUDPV4TRANS_RTCPRECEIVEBUFFER; }
+
+ /** Sets the IP address which is used to bind the sockets to \c ip. */
+ void SetBindIP(uint32_t ip) { bindIP = ip; }
+
+ /** Sets the multicast interface IP address. */
+ void SetMulticastInterfaceIP(uint32_t ip) { mcastifaceIP = ip; }
+
+ /** Sets the RTP portbase to \c pbase. This has to be an even number. */
+ void SetPortbase(uint16_t pbase) { portbase = pbase; }
+
+ /** Sets the multicast TTL to be used to \c mcastTTL. */
+ void SetMulticastTTL(uint8_t mcastTTL) { multicastTTL = mcastTTL; }
+
+ /** Passes a list of IP addresses which will be used as the local IP addresses. */
+ void SetLocalIPList(std::list<uint32_t> &iplist) { localIPs = iplist; }
+
+ /** Clears the list of local IP addresses.
+ * Clears the list of local IP addresses. An empty list will make the transmission
+ * component itself determine the local IP addresses.
+ */
+ void ClearLocalIPList() { localIPs.clear(); }
+
+ /** Returns the IP address which will be used to bind the sockets. */
+ uint32_t GetBindIP() const { return bindIP; }
+
+ /** Returns the multicast interface IP address. */
+ uint32_t GetMulticastInterfaceIP() const { return mcastifaceIP; }
+
+ /** Returns the RTP portbase which will be used (default is 5000). */
+ uint16_t GetPortbase() const { return portbase; }
+
+ /** Returns the multicast TTL which will be used (default is 1). */
+ uint8_t GetMulticastTTL() const { return multicastTTL; }
+
+ /** Returns the list of local IP addresses. */
+ const std::list<uint32_t> &GetLocalIPList() const { return localIPs; }
+
+ /** Sets the RTP socket's send buffer size. */
+ void SetRTPSendBuffer(int s) { rtpsendbuf = s; }
+
+ /** Sets the RTP socket's receive buffer size. */
+ void SetRTPReceiveBuffer(int s) { rtprecvbuf = s; }
+
+ /** Sets the RTCP socket's send buffer size. */
+ void SetRTCPSendBuffer(int s) { rtcpsendbuf = s; }
+
+ /** Sets the RTCP socket's receive buffer size. */
+ void SetRTCPReceiveBuffer(int s) { rtcprecvbuf = s; }
+
+ /** Returns the RTP socket's send buffer size. */
+ int GetRTPSendBuffer() const { return rtpsendbuf; }
+
+ /** Returns the RTP socket's receive buffer size. */
+ int GetRTPReceiveBuffer() const { return rtprecvbuf; }
+
+ /** Returns the RTCP socket's send buffer size. */
+ int GetRTCPSendBuffer() const { return rtcpsendbuf; }
+
+ /** Returns the RTCP socket's receive buffer size. */
+ int GetRTCPReceiveBuffer() const { return rtcprecvbuf; }
+private:
+ uint16_t portbase;
+ uint32_t bindIP, mcastifaceIP;
+ std::list<uint32_t> localIPs;
+ uint8_t multicastTTL;
+ int rtpsendbuf, rtprecvbuf;
+ int rtcpsendbuf, rtcprecvbuf;
+};
+
+/** Additional information about the UDP over IPv4 transmitter. */
+class RTPUDPv4TransmissionInfo : public RTPTransmissionInfo
+{
+public:
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ RTPUDPv4TransmissionInfo(std::list<uint32_t> iplist,int rtpsock,int rtcpsock) : RTPTransmissionInfo(RTPTransmitter::IPv4UDPProto)
+#else
+ RTPUDPv4TransmissionInfo(std::list<uint32_t> iplist,SOCKET rtpsock,SOCKET rtcpsock) : RTPTransmissionInfo(RTPTransmitter::IPv4UDPProto)
+#endif // WIN32
+ { localIPlist = iplist; rtpsocket = rtpsock; rtcpsocket = rtcpsock; }
+
+ ~RTPUDPv4TransmissionInfo() { }
+
+ /** Returns the list of IPv4 addresses the transmitter considers to be the local IP addresses. */
+ std::list<uint32_t> GetLocalIPList() const { return localIPlist; }
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ /** Returns the socket descriptor used for receiving and transmitting RTP packets. */
+ int GetRTPSocket() const { return rtpsocket; }
+
+ /** Returns the socket descriptor used for receiving and transmitting RTCP packets. */
+ int GetRTCPSocket() const { return rtcpsocket; }
+#else
+ SOCKET GetRTPSocket() const { return rtpsocket; }
+ SOCKET GetRTCPSocket() const { return rtcpsocket; }
+#endif // WIN32
+private:
+ std::list<uint32_t> localIPlist;
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ int rtpsocket,rtcpsocket;
+#else
+ SOCKET rtpsocket,rtcpsocket;
+#endif // WIN32
+};
+
+class RTPUDPv4Trans_GetHashIndex_IPv4Dest
+{
+public:
+ static int GetIndex(const RTPIPv4Destination &d) { return d.GetIP()%RTPUDPV4TRANS_HASHSIZE; }
+};
+
+class RTPUDPv4Trans_GetHashIndex_uint32_t
+{
+public:
+ static int GetIndex(const uint32_t &k) { return k%RTPUDPV4TRANS_HASHSIZE; }
+};
+
+#define RTPUDPV4TRANS_HEADERSIZE (20+8)
+
+/** An UDP over IPv4 transmission component.
+ * This class inherits the RTPTransmitter interface and implements a transmission component
+ * which uses UDP over IPv4 to send and receive RTP and RTCP data. The component's parameters
+ * are described by the class RTPUDPv4TransmissionParams. The functions which have an RTPAddress
+ * argument require an argument of RTPIPv4Address. The GetTransmissionInfo member function
+ * returns an instance of type RTPUDPv4TransmissionInfo.
+ */
+class RTPUDPv4Transmitter : public RTPTransmitter
+{
+public:
+ RTPUDPv4Transmitter(RTPMemoryManager *mgr);
+ ~RTPUDPv4Transmitter();
+
+ int Init(bool treadsafe);
+ int Create(size_t maxpacksize,const RTPTransmissionParams *transparams);
+ void Destroy();
+ RTPTransmissionInfo *GetTransmissionInfo();
+
+ int GetLocalHostName(uint8_t *buffer,size_t *bufferlength);
+ bool ComesFromThisTransmitter(const RTPAddress *addr);
+ size_t GetHeaderOverhead() { return RTPUDPV4TRANS_HEADERSIZE; }
+
+ int Poll();
+ int WaitForIncomingData(const RTPTime &delay,bool *dataavailable = 0);
+ int AbortWait();
+
+ int SendRTPData(const void *data,size_t len);
+ int SendRTCPData(const void *data,size_t len);
+
+ int AddDestination(const RTPAddress &addr);
+ int DeleteDestination(const RTPAddress &addr);
+ void ClearDestinations();
+
+ bool SupportsMulticasting();
+ int JoinMulticastGroup(const RTPAddress &addr);
+ int LeaveMulticastGroup(const RTPAddress &addr);
+ void LeaveAllMulticastGroups();
+
+ int SetReceiveMode(RTPTransmitter::ReceiveMode m);
+ int AddToIgnoreList(const RTPAddress &addr);
+ int DeleteFromIgnoreList(const RTPAddress &addr);
+ void ClearIgnoreList();
+ int AddToAcceptList(const RTPAddress &addr);
+ int DeleteFromAcceptList(const RTPAddress &addr);
+ void ClearAcceptList();
+ int SetMaximumPacketSize(size_t s);
+
+ bool NewDataAvailable();
+ RTPRawPacket *GetNextPacket();
+#ifdef RTPDEBUG
+ void Dump();
+#endif // RTPDEBUG
+private:
+ int CreateLocalIPList();
+ bool GetLocalIPList_Interfaces();
+ void GetLocalIPList_DNS();
+ void AddLoopbackAddress();
+ void FlushPackets();
+ int PollSocket(bool rtp);
+ int ProcessAddAcceptIgnoreEntry(uint32_t ip,uint16_t port);
+ int ProcessDeleteAcceptIgnoreEntry(uint32_t ip,uint16_t port);
+#ifdef RTP_SUPPORT_IPV4MULTICAST
+ bool SetMulticastTTL(uint8_t ttl);
+#endif // RTP_SUPPORT_IPV4MULTICAST
+ bool ShouldAcceptData(uint32_t srcip,uint16_t srcport);
+ void ClearAcceptIgnoreInfo();
+
+ bool init;
+ bool created;
+ bool waitingfordata;
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ SOCKET rtpsock,rtcpsock;
+#else // not using winsock
+ int rtpsock,rtcpsock;
+#endif // WIN32
+ uint32_t bindIP, mcastifaceIP;
+ std::list<uint32_t> localIPs;
+ uint16_t portbase;
+ uint8_t multicastTTL;
+ RTPTransmitter::ReceiveMode receivemode;
+
+ uint8_t *localhostname;
+ size_t localhostnamelength;
+
+ RTPHashTable<const RTPIPv4Destination,RTPUDPv4Trans_GetHashIndex_IPv4Dest,RTPUDPV4TRANS_HASHSIZE> destinations;
+#ifdef RTP_SUPPORT_IPV4MULTICAST
+ RTPHashTable<const uint32_t,RTPUDPv4Trans_GetHashIndex_uint32_t,RTPUDPV4TRANS_HASHSIZE> multicastgroups;
+#endif // RTP_SUPPORT_IPV4MULTICAST
+ std::list<RTPRawPacket*> rawpacketlist;
+
+ bool supportsmulticasting;
+ size_t maxpacksize;
+
+ class PortInfo
+ {
+ public:
+ PortInfo() { all = false; }
+
+ bool all;
+ std::list<uint16_t> portlist;
+ };
+
+ RTPKeyHashTable<const uint32_t,PortInfo*,RTPUDPv4Trans_GetHashIndex_uint32_t,RTPUDPV4TRANS_HASHSIZE> acceptignoreinfo;
+
+ // notification descriptors for AbortWait (0 is for reading, 1 for writing)
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ SOCKET abortdesc[2];
+#else
+ int abortdesc[2];
+#endif // WIN32
+ int CreateAbortDescriptors();
+ void DestroyAbortDescriptors();
+ void AbortWaitInternal();
+#ifdef RTP_SUPPORT_THREAD
+ JMutex mainmutex,waitmutex;
+ int threadsafe;
+#endif // RTP_SUPPORT_THREAD
+};
+
+#endif // RTPUDPV4TRANSMITTER_H
+
diff --git a/src/rtpudpv6transmitter.cpp b/src/rtpudpv6transmitter.cpp
new file mode 100644
index 0000000..6bf04d4
--- /dev/null
+++ b/src/rtpudpv6transmitter.cpp
@@ -0,0 +1,1889 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtpudpv6transmitter.h"
+
+#ifdef RTP_SUPPORT_IPV6
+
+#include "rtprawpacket.h"
+#include "rtpipv6address.h"
+#include "rtptimeutilities.h"
+#include "rtpdefines.h"
+#include <stdio.h>
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ #define RTPSOCKERR INVALID_SOCKET
+ #define RTPCLOSE(x) closesocket(x)
+ #define RTPSOCKLENTYPE int
+ #define RTPIOCTL ioctlsocket
+#else // not Win32
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <sys/ioctl.h>
+ #include <net/if.h>
+ #include <string.h>
+ #include <netdb.h>
+ #include <unistd.h>
+
+ #ifdef RTP_HAVE_SYS_FILIO
+ #include <sys/filio.h>
+ #endif // RTP_HAVE_SYS_FILIO
+ #ifdef RTP_HAVE_SYS_SOCKIO
+ #include <sys/sockio.h>
+ #endif // RTP_HAVE_SYS_SOCKIO
+ #ifdef RTP_SUPPORT_IFADDRS
+ #include <ifaddrs.h>
+ #endif // RTP_SUPPORT_IFADDRS
+
+
+ #define RTPSOCKERR -1
+ #define RTPCLOSE(x) close(x)
+
+ #ifdef RTP_SOCKLENTYPE_UINT
+ #define RTPSOCKLENTYPE unsigned int
+ #else
+ #define RTPSOCKLENTYPE int
+ #endif // RTP_SOCKLENTYPE_UINT
+
+ #define RTPIOCTL ioctl
+#endif // WIN32
+
+#include "rtpdebug.h"
+
+#define RTPUDPV6TRANS_MAXPACKSIZE 65535
+#define RTPUDPV6TRANS_IFREQBUFSIZE 8192
+
+#define RTPUDPV6TRANS_IS_MCASTADDR(x) (x.s6_addr[0] == 0xFF)
+
+#define RTPUDPV6TRANS_MCASTMEMBERSHIP(socket,type,mcastip,status) {\
+ struct ipv6_mreq mreq;\
+ \
+ mreq.ipv6mr_multiaddr = mcastip;\
+ mreq.ipv6mr_interface = mcastifidx;\
+ status = setsockopt(socket,IPPROTO_IPV6,type,(const char *)&mreq,sizeof(struct ipv6_mreq));\
+ }
+#ifdef RTP_SUPPORT_THREAD
+ #define MAINMUTEX_LOCK { if (threadsafe) mainmutex.Lock(); }
+ #define MAINMUTEX_UNLOCK { if (threadsafe) mainmutex.Unlock(); }
+ #define WAITMUTEX_LOCK { if (threadsafe) waitmutex.Lock(); }
+ #define WAITMUTEX_UNLOCK { if (threadsafe) waitmutex.Unlock(); }
+#else
+ #define MAINMUTEX_LOCK
+ #define MAINMUTEX_UNLOCK
+ #define WAITMUTEX_LOCK
+ #define WAITMUTEX_UNLOCK
+#endif // RTP_SUPPORT_THREAD
+
+inline bool operator==(const in6_addr &ip1,const in6_addr &ip2)
+{
+ if (memcmp(&ip1,&ip2,sizeof(in6_addr)) == 0)
+ return true;
+ return false;
+}
+
+RTPUDPv6Transmitter::RTPUDPv6Transmitter(RTPMemoryManager *mgr) : RTPTransmitter(mgr),
+ destinations(GetMemoryManager(),RTPMEM_TYPE_CLASS_DESTINATIONLISTHASHELEMENT),
+ multicastgroups(GetMemoryManager(),RTPMEM_TYPE_CLASS_MULTICASTHASHELEMENT),
+ acceptignoreinfo(GetMemoryManager(),RTPMEM_TYPE_CLASS_ACCEPTIGNOREHASHELEMENT)
+{
+ created = false;
+ init = false;
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ timeinit.Dummy();
+#endif // WIN32 || _WIN32_WCE
+}
+
+RTPUDPv6Transmitter::~RTPUDPv6Transmitter()
+{
+ Destroy();
+}
+
+int RTPUDPv6Transmitter::Init(bool tsafe)
+{
+ if (init)
+ return ERR_RTP_UDPV6TRANS_ALREADYINIT;
+
+#ifdef RTP_SUPPORT_THREAD
+ threadsafe = tsafe;
+ if (threadsafe)
+ {
+ int status;
+
+ status = mainmutex.Init();
+ if (status < 0)
+ return ERR_RTP_UDPV6TRANS_CANTINITMUTEX;
+ status = waitmutex.Init();
+ if (status < 0)
+ return ERR_RTP_UDPV6TRANS_CANTINITMUTEX;
+ }
+#else
+ if (tsafe)
+ return ERR_RTP_NOTHREADSUPPORT;
+#endif // RTP_SUPPORT_THREAD
+
+ init = true;
+ return 0;
+}
+
+int RTPUDPv6Transmitter::Create(size_t maximumpacketsize,const RTPTransmissionParams *transparams)
+{
+ const RTPUDPv6TransmissionParams *params,defaultparams;
+ struct sockaddr_in6 addr;
+ RTPSOCKLENTYPE size;
+ int status;
+
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_ALREADYCREATED;
+ }
+
+ // Obtain transmission parameters
+
+ if (transparams == 0)
+ params = &defaultparams;
+ else
+ {
+ if (transparams->GetTransmissionProtocol() != RTPTransmitter::IPv6UDPProto)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_ILLEGALPARAMETERS;
+ }
+ params = (const RTPUDPv6TransmissionParams *)transparams;
+ }
+
+ // Check if portbase is even
+ if (params->GetPortbase()%2 != 0)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_PORTBASENOTEVEN;
+ }
+
+ // create sockets
+
+ rtpsock = socket(PF_INET6,SOCK_DGRAM,0);
+ if (rtpsock == RTPSOCKERR)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTCREATESOCKET;
+ }
+ rtcpsock = socket(PF_INET6,SOCK_DGRAM,0);
+ if (rtcpsock == RTPSOCKERR)
+ {
+ RTPCLOSE(rtpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTCREATESOCKET;
+ }
+
+ // set socket buffer sizes
+
+ size = params->GetRTPReceiveBuffer();
+ if (setsockopt(rtpsock,SOL_SOCKET,SO_RCVBUF,(const char *)&size,sizeof(int)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTSETRTPRECEIVEBUF;
+ }
+ size = params->GetRTPSendBuffer();
+ if (setsockopt(rtpsock,SOL_SOCKET,SO_SNDBUF,(const char *)&size,sizeof(int)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTSETRTPTRANSMITBUF;
+ }
+ size = params->GetRTCPReceiveBuffer();
+ if (setsockopt(rtcpsock,SOL_SOCKET,SO_RCVBUF,(const char *)&size,sizeof(int)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTSETRTCPRECEIVEBUF;
+ }
+ size = params->GetRTCPSendBuffer();
+ if (setsockopt(rtcpsock,SOL_SOCKET,SO_SNDBUF,(const char *)&size,sizeof(int)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTSETRTCPTRANSMITBUF;
+ }
+
+ // bind sockets
+
+ bindIP = params->GetBindIP();
+ mcastifidx = params->GetMulticastInterfaceIndex();
+
+ memset(&addr,0,sizeof(struct sockaddr_in6));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons(params->GetPortbase());
+ addr.sin6_addr = bindIP;
+ if (bind(rtpsock,(struct sockaddr *)&addr,sizeof(struct sockaddr_in6)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTBINDRTPSOCKET;
+ }
+ memset(&addr,0,sizeof(struct sockaddr_in6));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons(params->GetPortbase()+1);
+ addr.sin6_addr = bindIP;
+ if (bind(rtcpsock,(struct sockaddr *)&addr,sizeof(struct sockaddr_in6)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTBINDRTCPSOCKET;
+ }
+
+ // Try to obtain local IP addresses
+
+ localIPs = params->GetLocalIPList();
+ if (localIPs.empty()) // User did not provide list of local IP addresses, calculate them
+ {
+ int status;
+
+ if ((status = CreateLocalIPList()) < 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return status;
+ }
+
+#ifdef RTPDEBUG
+ std::cout << "Found these local IP addresses:" << std::endl;
+
+ std::list<in6_addr>::const_iterator it;
+
+ for (it = localIPs.begin() ; it != localIPs.end() ; it++)
+ {
+ RTPIPv6Address a(*it);
+
+ std::cout << a.GetAddressString() << std::endl;
+ }
+#endif // RTPDEBUG
+ }
+
+#ifdef RTP_SUPPORT_IPV6MULTICAST
+ if (SetMulticastTTL(params->GetMulticastTTL()))
+ supportsmulticasting = true;
+ else
+ supportsmulticasting = false;
+#else // no multicast support enabled
+ supportsmulticasting = false;
+#endif // RTP_SUPPORT_IPV6MULTICAST
+
+ if ((status = CreateAbortDescriptors()) < 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return status;
+ }
+
+ if (maximumpacketsize > RTPUDPV6TRANS_MAXPACKSIZE)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ DestroyAbortDescriptors();
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_SPECIFIEDSIZETOOBIG;
+ }
+
+ maxpacksize = maximumpacketsize;
+ portbase = params->GetPortbase();
+ multicastTTL = params->GetMulticastTTL();
+ receivemode = RTPTransmitter::AcceptAll;
+
+ localhostname = 0;
+ localhostnamelength = 0;
+
+ waitingfordata = false;
+ created = true;
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+void RTPUDPv6Transmitter::Destroy()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK;
+ return;
+ }
+
+ if (localhostname)
+ {
+ RTPDeleteByteArray(localhostname,GetMemoryManager());
+ localhostname = 0;
+ localhostnamelength = 0;
+ }
+
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ destinations.Clear();
+#ifdef RTP_SUPPORT_IPV6MULTICAST
+ multicastgroups.Clear();
+#endif // RTP_SUPPORT_IPV6MULTICAST
+ FlushPackets();
+ ClearAcceptIgnoreInfo();
+ localIPs.clear();
+ created = false;
+
+ if (waitingfordata)
+ {
+ AbortWaitInternal();
+ DestroyAbortDescriptors();
+ MAINMUTEX_UNLOCK
+ WAITMUTEX_LOCK // to make sure that the WaitForIncomingData function ended
+ WAITMUTEX_UNLOCK
+ }
+ else
+ DestroyAbortDescriptors();
+
+ MAINMUTEX_UNLOCK
+}
+
+RTPTransmissionInfo *RTPUDPv6Transmitter::GetTransmissionInfo()
+{
+ if (!init)
+ return 0;
+
+ MAINMUTEX_LOCK
+ RTPTransmissionInfo *tinf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPTRANSMISSIONINFO) RTPUDPv6TransmissionInfo(localIPs,rtpsock,rtcpsock);
+ MAINMUTEX_UNLOCK
+ return tinf;
+}
+
+int RTPUDPv6Transmitter::GetLocalHostName(uint8_t *buffer,size_t *bufferlength)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+
+ if (localhostname == 0)
+ {
+ if (localIPs.empty())
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOLOCALIPS;
+ }
+
+ std::list<in6_addr>::const_iterator it;
+ std::list<std::string> hostnames;
+
+ for (it = localIPs.begin() ; it != localIPs.end() ; it++)
+ {
+ bool founddouble = false;
+ bool foundentry = true;
+
+ while (!founddouble && foundentry)
+ {
+ struct hostent *he;
+ in6_addr ip = (*it);
+
+ he = gethostbyaddr((char *)&ip,sizeof(in6_addr),AF_INET6);
+ if (he != 0)
+ {
+ std::string hname = std::string(he->h_name);
+ std::list<std::string>::const_iterator it;
+
+ for (it = hostnames.begin() ; !founddouble && it != hostnames.end() ; it++)
+ if ((*it) == hname)
+ founddouble = true;
+
+ if (!founddouble)
+ hostnames.push_back(hname);
+
+ int i = 0;
+ while (!founddouble && he->h_aliases[i] != 0)
+ {
+ std::string hname = std::string(he->h_aliases[i]);
+
+ for (it = hostnames.begin() ; !founddouble && it != hostnames.end() ; it++)
+ if ((*it) == hname)
+ founddouble = true;
+
+ if (!founddouble)
+ {
+ hostnames.push_back(hname);
+ i++;
+ }
+ }
+ }
+ else
+ foundentry = false;
+ }
+ }
+
+ bool found = false;
+
+ if (!hostnames.empty()) // try to select the most appropriate hostname
+ {
+ std::list<std::string>::const_iterator it;
+
+ hostnames.sort();
+ for (it = hostnames.begin() ; !found && it != hostnames.end() ; it++)
+ {
+ if ((*it).find('.') != std::string::npos)
+ {
+ found = true;
+ localhostnamelength = (*it).length();
+ localhostname = RTPNew(GetMemoryManager(),RTPMEM_TYPE_OTHER) uint8_t [localhostnamelength+1];
+ if (localhostname == 0)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_OUTOFMEM;
+ }
+ memcpy(localhostname,(*it).c_str(),localhostnamelength);
+ localhostname[localhostnamelength] = 0;
+ }
+ }
+ }
+
+ if (!found) // use an IP address
+ {
+ in6_addr ip;
+ int len;
+ char str[48];
+ uint16_t ip16[8];
+ int i,j;
+
+ it = localIPs.begin();
+ ip = (*it);
+
+ for (i = 0,j = 0 ; j < 8 ; j++,i += 2)
+ {
+ ip16[j] = (((uint16_t)ip.s6_addr[i])<<8);
+ ip16[j] |= ((uint16_t)ip.s6_addr[i+1]);
+ }
+
+ RTP_SNPRINTF(str,48,"%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",(int)ip16[0],(int)ip16[1],(int)ip16[2],(int)ip16[3],(int)ip16[4],(int)ip16[5],(int)ip16[6],(int)ip16[7]);
+ len = strlen(str);
+
+ localhostnamelength = len;
+ localhostname = RTPNew(GetMemoryManager(),RTPMEM_TYPE_OTHER) uint8_t [localhostnamelength+1];
+ if (localhostname == 0)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_OUTOFMEM;
+ }
+ memcpy(localhostname,str,localhostnamelength);
+ localhostname[localhostnamelength] = 0;
+ }
+ }
+
+ if ((*bufferlength) < localhostnamelength)
+ {
+ *bufferlength = localhostnamelength; // tell the application the required size of the buffer
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_TRANS_BUFFERLENGTHTOOSMALL;
+ }
+
+ memcpy(buffer,localhostname,localhostnamelength);
+ *bufferlength = localhostnamelength;
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+bool RTPUDPv6Transmitter::ComesFromThisTransmitter(const RTPAddress *addr)
+{
+ if (!init)
+ return false;
+
+ if (addr == 0)
+ return false;
+
+ MAINMUTEX_LOCK
+
+ bool v;
+
+ if (created && addr->GetAddressType() == RTPAddress::IPv6Address)
+ {
+ const RTPIPv6Address *addr2 = (const RTPIPv6Address *)addr;
+ bool found = false;
+ std::list<in6_addr>::const_iterator it;
+
+ it = localIPs.begin();
+ while (!found && it != localIPs.end())
+ {
+ in6_addr itip = *it;
+ in6_addr addrip = addr2->GetIP();
+ if (memcmp(&addrip,&itip,sizeof(in6_addr)) == 0)
+ found = true;
+ else
+ ++it;
+ }
+
+ if (!found)
+ v = false;
+ else
+ {
+ if (addr2->GetPort() == portbase) // check for RTP port
+ v = true;
+ else if (addr2->GetPort() == (portbase+1)) // check for RTCP port
+ v = true;
+ else
+ v = false;
+ }
+ }
+ else
+ v = false;
+
+ MAINMUTEX_UNLOCK
+ return v;
+}
+
+int RTPUDPv6Transmitter::Poll()
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ int status;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ status = PollSocket(true); // poll RTP socket
+ if (status >= 0)
+ status = PollSocket(false); // poll RTCP socket
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPUDPv6Transmitter::WaitForIncomingData(const RTPTime &delay,bool *dataavailable)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ fd_set fdset;
+ struct timeval tv;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (waitingfordata)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_ALREADYWAITING;
+ }
+
+ FD_ZERO(&fdset);
+ FD_SET(rtpsock,&fdset);
+ FD_SET(rtcpsock,&fdset);
+ FD_SET(abortdesc[0],&fdset);
+ tv.tv_sec = delay.GetSeconds();
+ tv.tv_usec = delay.GetMicroSeconds();
+
+ waitingfordata = true;
+
+ WAITMUTEX_LOCK
+ MAINMUTEX_UNLOCK
+
+ if (select(FD_SETSIZE,&fdset,0,0,&tv) < 0)
+ {
+ MAINMUTEX_LOCK
+ waitingfordata = false;
+ MAINMUTEX_UNLOCK
+ WAITMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_ERRORINSELECT;
+ }
+
+ MAINMUTEX_LOCK
+ waitingfordata = false;
+ if (!created) // destroy called
+ {
+ MAINMUTEX_UNLOCK;
+ WAITMUTEX_UNLOCK
+ return 0;
+ }
+
+ // if aborted, read from abort buffer
+ if (FD_ISSET(abortdesc[0],&fdset))
+ {
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ char buf[1];
+
+ recv(abortdesc[0],buf,1,0);
+#else
+ unsigned char buf[1];
+
+ read(abortdesc[0],buf,1);
+#endif // WIN32
+ }
+
+ if (dataavailable != 0)
+ {
+ if (FD_ISSET(rtpsock,&fdset) || FD_ISSET(rtcpsock,&fdset))
+ *dataavailable = true;
+ else
+ *dataavailable = false;
+ }
+
+ MAINMUTEX_UNLOCK
+ WAITMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPUDPv6Transmitter::AbortWait()
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (!waitingfordata)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTWAITING;
+ }
+
+ AbortWaitInternal();
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPUDPv6Transmitter::SendRTPData(const void *data,size_t len)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (len > maxpacksize)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_SPECIFIEDSIZETOOBIG;
+ }
+
+ destinations.GotoFirstElement();
+ while (destinations.HasCurrentElement())
+ {
+ sendto(rtpsock,(const char *)data,len,0,(const struct sockaddr *)destinations.GetCurrentElement().GetRTPSockAddr(),sizeof(struct sockaddr_in6));
+ destinations.GotoNextElement();
+ }
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPUDPv6Transmitter::SendRTCPData(const void *data,size_t len)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (len > maxpacksize)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_SPECIFIEDSIZETOOBIG;
+ }
+
+ destinations.GotoFirstElement();
+ while (destinations.HasCurrentElement())
+ {
+ sendto(rtcpsock,(const char *)data,len,0,(const struct sockaddr *)destinations.GetCurrentElement().GetRTCPSockAddr(),sizeof(struct sockaddr_in6));
+ destinations.GotoNextElement();
+ }
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPUDPv6Transmitter::AddDestination(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+
+ RTPIPv6Address &address = (RTPIPv6Address &)addr;
+ RTPIPv6Destination dest(address.GetIP(),address.GetPort());
+ int status = destinations.AddElement(dest);
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPUDPv6Transmitter::DeleteDestination(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+
+ RTPIPv6Address &address = (RTPIPv6Address &)addr;
+ RTPIPv6Destination dest(address.GetIP(),address.GetPort());
+ int status = destinations.DeleteElement(dest);
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+void RTPUDPv6Transmitter::ClearDestinations()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created)
+ destinations.Clear();
+ MAINMUTEX_UNLOCK
+}
+
+bool RTPUDPv6Transmitter::SupportsMulticasting()
+{
+ if (!init)
+ return false;
+
+ MAINMUTEX_LOCK
+
+ bool v;
+
+ if (!created)
+ v = false;
+ else
+ v = supportsmulticasting;
+
+ MAINMUTEX_UNLOCK
+ return v;
+}
+
+#ifdef RTP_SUPPORT_IPV6MULTICAST
+
+int RTPUDPv6Transmitter::JoinMulticastGroup(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+
+ const RTPIPv6Address &address = (const RTPIPv6Address &)addr;
+ in6_addr mcastIP = address.GetIP();
+
+ if (!RTPUDPV6TRANS_IS_MCASTADDR(mcastIP))
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTAMULTICASTADDRESS;
+ }
+
+ status = multicastgroups.AddElement(mcastIP);
+ if (status >= 0)
+ {
+ RTPUDPV6TRANS_MCASTMEMBERSHIP(rtpsock,IPV6_JOIN_GROUP,mcastIP,status);
+ if (status != 0)
+ {
+ multicastgroups.DeleteElement(mcastIP);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_COULDNTJOINMULTICASTGROUP;
+ }
+ RTPUDPV6TRANS_MCASTMEMBERSHIP(rtcpsock,IPV6_JOIN_GROUP,mcastIP,status);
+ if (status != 0)
+ {
+ RTPUDPV6TRANS_MCASTMEMBERSHIP(rtpsock,IPV6_LEAVE_GROUP,mcastIP,status);
+ multicastgroups.DeleteElement(mcastIP);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_COULDNTJOINMULTICASTGROUP;
+ }
+ }
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPUDPv6Transmitter::LeaveMulticastGroup(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+
+ const RTPIPv6Address &address = (const RTPIPv6Address &)addr;
+ in6_addr mcastIP = address.GetIP();
+
+ if (!RTPUDPV6TRANS_IS_MCASTADDR(mcastIP))
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTAMULTICASTADDRESS;
+ }
+
+ status = multicastgroups.DeleteElement(mcastIP);
+ if (status >= 0)
+ {
+ RTPUDPV6TRANS_MCASTMEMBERSHIP(rtpsock,IPV6_LEAVE_GROUP,mcastIP,status);
+ RTPUDPV6TRANS_MCASTMEMBERSHIP(rtcpsock,IPV6_LEAVE_GROUP,mcastIP,status);
+ status = 0;
+ }
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+void RTPUDPv6Transmitter::LeaveAllMulticastGroups()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created)
+ {
+ multicastgroups.GotoFirstElement();
+ while (multicastgroups.HasCurrentElement())
+ {
+ in6_addr mcastIP;
+ int status = 0;
+
+ mcastIP = multicastgroups.GetCurrentElement();
+ RTPUDPV6TRANS_MCASTMEMBERSHIP(rtpsock,IPV6_LEAVE_GROUP,mcastIP,status);
+ RTPUDPV6TRANS_MCASTMEMBERSHIP(rtcpsock,IPV6_LEAVE_GROUP,mcastIP,status);
+ multicastgroups.GotoNextElement();
+ }
+ multicastgroups.Clear();
+ }
+ MAINMUTEX_UNLOCK
+}
+
+#else // no multicast support
+
+int RTPUDPv6Transmitter::JoinMulticastGroup(const RTPAddress &addr)
+{
+ return ERR_RTP_UDPV6TRANS_NOMULTICASTSUPPORT;
+}
+
+int RTPUDPv6Transmitter::LeaveMulticastGroup(const RTPAddress &addr)
+{
+ return ERR_RTP_UDPV6TRANS_NOMULTICASTSUPPORT;
+}
+
+void RTPUDPv6Transmitter::LeaveAllMulticastGroups()
+{
+}
+
+#endif // RTP_SUPPORT_IPV6MULTICAST
+
+int RTPUDPv6Transmitter::SetReceiveMode(RTPTransmitter::ReceiveMode m)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (m != receivemode)
+ {
+ receivemode = m;
+ acceptignoreinfo.Clear();
+ }
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPUDPv6Transmitter::AddToIgnoreList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::IgnoreSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv6Address &address = (const RTPIPv6Address &)addr;
+ status = ProcessAddAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPUDPv6Transmitter::DeleteFromIgnoreList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::IgnoreSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv6Address &address = (const RTPIPv6Address &)addr;
+ status = ProcessDeleteAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+void RTPUDPv6Transmitter::ClearIgnoreList()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created && receivemode == RTPTransmitter::IgnoreSome)
+ ClearAcceptIgnoreInfo();
+ MAINMUTEX_UNLOCK
+}
+
+int RTPUDPv6Transmitter::AddToAcceptList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::AcceptSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv6Address &address = (const RTPIPv6Address &)addr;
+ status = ProcessAddAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPUDPv6Transmitter::DeleteFromAcceptList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::AcceptSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv6Address &address = (const RTPIPv6Address &)addr;
+ status = ProcessDeleteAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+void RTPUDPv6Transmitter::ClearAcceptList()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created && receivemode == RTPTransmitter::AcceptSome)
+ ClearAcceptIgnoreInfo();
+ MAINMUTEX_UNLOCK
+}
+
+int RTPUDPv6Transmitter::SetMaximumPacketSize(size_t s)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (s > RTPUDPV6TRANS_MAXPACKSIZE)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_SPECIFIEDSIZETOOBIG;
+ }
+ maxpacksize = s;
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+bool RTPUDPv6Transmitter::NewDataAvailable()
+{
+ if (!init)
+ return false;
+
+ MAINMUTEX_LOCK
+
+ bool v;
+
+ if (!created)
+ v = false;
+ else
+ {
+ if (rawpacketlist.empty())
+ v = false;
+ else
+ v = true;
+ }
+
+ MAINMUTEX_UNLOCK
+ return v;
+}
+
+RTPRawPacket *RTPUDPv6Transmitter::GetNextPacket()
+{
+ if (!init)
+ return 0;
+
+ MAINMUTEX_LOCK
+
+ RTPRawPacket *p;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return 0;
+ }
+ if (rawpacketlist.empty())
+ {
+ MAINMUTEX_UNLOCK
+ return 0;
+ }
+
+ p = *(rawpacketlist.begin());
+ rawpacketlist.pop_front();
+
+ MAINMUTEX_UNLOCK
+ return p;
+}
+
+// Here the private functions start...
+
+
+#ifdef RTP_SUPPORT_IPV6MULTICAST
+bool RTPUDPv6Transmitter::SetMulticastTTL(uint8_t ttl)
+{
+ int ttl2,status;
+
+ ttl2 = (int)ttl;
+ status = setsockopt(rtpsock,IPPROTO_IPV6,IPV6_MULTICAST_HOPS,(const char *)&ttl2,sizeof(int));
+ if (status != 0)
+ return false;
+ status = setsockopt(rtcpsock,IPPROTO_IPV6,IPV6_MULTICAST_HOPS,(const char *)&ttl2,sizeof(int));
+ if (status != 0)
+ return false;
+ return true;
+}
+#endif // RTP_SUPPORT_IPV6MULTICAST
+
+
+void RTPUDPv6Transmitter::FlushPackets()
+{
+ std::list<RTPRawPacket*>::const_iterator it;
+
+ for (it = rawpacketlist.begin() ; it != rawpacketlist.end() ; ++it)
+ RTPDelete(*it,GetMemoryManager());
+ rawpacketlist.clear();
+}
+
+int RTPUDPv6Transmitter::PollSocket(bool rtp)
+{
+ RTPSOCKLENTYPE fromlen;
+ int recvlen;
+ char packetbuffer[RTPUDPV6TRANS_MAXPACKSIZE];
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ SOCKET sock;
+ unsigned long len;
+#else
+ size_t len;
+ int sock;
+#endif // WIN32
+ struct sockaddr_in6 srcaddr;
+
+ if (rtp)
+ sock = rtpsock;
+ else
+ sock = rtcpsock;
+
+ len = 0;
+ RTPIOCTL(sock,FIONREAD,&len);
+ if (len <= 0)
+ return 0;
+
+ while (len > 0)
+ {
+ RTPTime curtime = RTPTime::CurrentTime();
+ fromlen = sizeof(struct sockaddr_in6);
+ recvlen = recvfrom(sock,packetbuffer,RTPUDPV6TRANS_MAXPACKSIZE,0,(struct sockaddr *)&srcaddr,&fromlen);
+ if (recvlen > 0)
+ {
+ bool acceptdata;
+
+ // got data, process it
+ if (receivemode == RTPTransmitter::AcceptAll)
+ acceptdata = true;
+ else
+ acceptdata = ShouldAcceptData(srcaddr.sin6_addr,ntohs(srcaddr.sin6_port));
+
+ if (acceptdata)
+ {
+ RTPRawPacket *pack;
+ RTPIPv6Address *addr;
+ uint8_t *datacopy;
+
+ addr = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPADDRESS) RTPIPv6Address(srcaddr.sin6_addr,ntohs(srcaddr.sin6_port));
+ if (addr == 0)
+ return ERR_RTP_OUTOFMEM;
+ datacopy = RTPNew(GetMemoryManager(),(rtp)?RTPMEM_TYPE_BUFFER_RECEIVEDRTPPACKET:RTPMEM_TYPE_BUFFER_RECEIVEDRTCPPACKET) uint8_t[recvlen];
+ if (datacopy == 0)
+ {
+ RTPDelete(addr,GetMemoryManager());
+ return ERR_RTP_OUTOFMEM;
+ }
+ memcpy(datacopy,packetbuffer,recvlen);
+
+ pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET) RTPRawPacket(datacopy,recvlen,addr,curtime,rtp,GetMemoryManager());
+ if (pack == 0)
+ {
+ RTPDelete(addr,GetMemoryManager());
+ RTPDeleteByteArray(datacopy,GetMemoryManager());
+ return ERR_RTP_OUTOFMEM;
+ }
+ rawpacketlist.push_back(pack);
+ }
+ }
+ len = 0;
+ RTPIOCTL(sock,FIONREAD,&len);
+ }
+ return 0;
+}
+
+int RTPUDPv6Transmitter::ProcessAddAcceptIgnoreEntry(in6_addr ip,uint16_t port)
+{
+ acceptignoreinfo.GotoElement(ip);
+ if (acceptignoreinfo.HasCurrentElement()) // An entry for this IP address already exists
+ {
+ PortInfo *portinf = acceptignoreinfo.GetCurrentElement();
+
+ if (port == 0) // select all ports
+ {
+ portinf->all = true;
+ portinf->portlist.clear();
+ }
+ else if (!portinf->all)
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = portinf->portlist.begin();
+ end = portinf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == port) // already in list
+ return 0;
+ }
+ portinf->portlist.push_front(port);
+ }
+ }
+ else // got to create an entry for this IP address
+ {
+ PortInfo *portinf;
+ int status;
+
+ portinf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_ACCEPTIGNOREPORTINFO) PortInfo();
+ if (port == 0) // select all ports
+ portinf->all = true;
+ else
+ portinf->portlist.push_front(port);
+
+ status = acceptignoreinfo.AddElement(ip,portinf);
+ if (status < 0)
+ {
+ RTPDelete(portinf,GetMemoryManager());
+ return status;
+ }
+ }
+ return 0;
+}
+
+void RTPUDPv6Transmitter::ClearAcceptIgnoreInfo()
+{
+ acceptignoreinfo.GotoFirstElement();
+ while (acceptignoreinfo.HasCurrentElement())
+ {
+ PortInfo *inf;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ RTPDelete(inf,GetMemoryManager());
+ acceptignoreinfo.GotoNextElement();
+ }
+ acceptignoreinfo.Clear();
+}
+
+int RTPUDPv6Transmitter::ProcessDeleteAcceptIgnoreEntry(in6_addr ip,uint16_t port)
+{
+ acceptignoreinfo.GotoElement(ip);
+ if (!acceptignoreinfo.HasCurrentElement())
+ return ERR_RTP_UDPV6TRANS_NOSUCHENTRY;
+
+ PortInfo *inf;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ if (port == 0) // delete all entries
+ {
+ inf->all = false;
+ inf->portlist.clear();
+ }
+ else // a specific port was selected
+ {
+ if (inf->all) // currently, all ports are selected. Add the one to remove to the list
+ {
+ // we have to check if the list doesn't contain the port already
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == port) // already in list: this means we already deleted the entry
+ return ERR_RTP_UDPV6TRANS_NOSUCHENTRY;
+ }
+ inf->portlist.push_front(port);
+ }
+ else // check if we can find the port in the list
+ {
+ std::list<uint16_t>::iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; ++it)
+ {
+ if (*it == port) // found it!
+ {
+ inf->portlist.erase(it);
+ return 0;
+ }
+ }
+ // didn't find it
+ return ERR_RTP_UDPV6TRANS_NOSUCHENTRY;
+ }
+ }
+ return 0;
+}
+
+bool RTPUDPv6Transmitter::ShouldAcceptData(in6_addr srcip,uint16_t srcport)
+{
+ if (receivemode == RTPTransmitter::AcceptSome)
+ {
+ PortInfo *inf;
+
+ acceptignoreinfo.GotoElement(srcip);
+ if (!acceptignoreinfo.HasCurrentElement())
+ return false;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ if (!inf->all) // only accept the ones in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return true;
+ }
+ return false;
+ }
+ else // accept all, except the ones in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return false;
+ }
+ return true;
+ }
+ }
+ else // IgnoreSome
+ {
+ PortInfo *inf;
+
+ acceptignoreinfo.GotoElement(srcip);
+ if (!acceptignoreinfo.HasCurrentElement())
+ return true;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ if (!inf->all) // ignore the ports in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return false;
+ }
+ return true;
+ }
+ else // ignore all, except the ones in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return true;
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
+#if (defined(WIN32) || defined(_WIN32_WCE))
+
+int RTPUDPv6Transmitter::CreateAbortDescriptors()
+{
+ SOCKET listensock;
+ int size;
+ struct sockaddr_in6 addr;
+
+ listensock = socket(PF_INET6,SOCK_STREAM,0);
+ if (listensock == RTPSOCKERR)
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+
+ memset(&addr,0,sizeof(struct sockaddr_in6));
+ addr.sin6_family = AF_INET6;
+ if (bind(listensock,(struct sockaddr *)&addr,sizeof(struct sockaddr_in6)) != 0)
+ {
+ RTPCLOSE(listensock);
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in6));
+ size = sizeof(struct sockaddr_in6);
+ if (getsockname(listensock,(struct sockaddr*)&addr,&size) != 0)
+ {
+ RTPCLOSE(listensock);
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ unsigned short connectport = ntohs(addr.sin6_port);
+
+ abortdesc[0] = socket(PF_INET6,SOCK_STREAM,0);
+ if (abortdesc[0] == RTPSOCKERR)
+ {
+ RTPCLOSE(listensock);
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in6));
+ addr.sin6_family = AF_INET6;
+ if (bind(abortdesc[0],(struct sockaddr *)&addr,sizeof(struct sockaddr_in6)) != 0)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ if (listen(listensock,1) != 0)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in6));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_addr = in6addr_loopback;
+ addr.sin6_port = htons(connectport);
+
+ if (connect(abortdesc[0],(struct sockaddr *)&addr,sizeof(struct sockaddr_in6)) != 0)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in6));
+ size = sizeof(struct sockaddr_in6);
+ abortdesc[1] = accept(listensock,(struct sockaddr *)&addr,&size);
+ if (abortdesc[1] == RTPSOCKERR)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ // okay, got the connection, close the listening socket
+
+ RTPCLOSE(listensock);
+ return 0;
+}
+
+void RTPUDPv6Transmitter::DestroyAbortDescriptors()
+{
+ RTPCLOSE(abortdesc[0]);
+ RTPCLOSE(abortdesc[1]);
+}
+
+#else // in a non winsock environment we can use pipes
+
+int RTPUDPv6Transmitter::CreateAbortDescriptors()
+{
+ if (pipe(abortdesc) < 0)
+ return ERR_RTP_UDPV6TRANS_CANTCREATEPIPE;
+ return 0;
+}
+
+void RTPUDPv6Transmitter::DestroyAbortDescriptors()
+{
+ close(abortdesc[0]);
+ close(abortdesc[1]);
+}
+
+#endif // WIN32
+
+int RTPUDPv6Transmitter::CreateLocalIPList()
+{
+ // first try to obtain the list from the network interface info
+
+ if (!GetLocalIPList_Interfaces())
+ {
+ // If this fails, we'll have to depend on DNS info
+ GetLocalIPList_DNS();
+ }
+ AddLoopbackAddress();
+ return 0;
+}
+
+#if (defined(WIN32) || defined(_WIN32_WCE))
+
+bool RTPUDPv6Transmitter::GetLocalIPList_Interfaces()
+{
+ unsigned char buffer[RTPUDPV6TRANS_IFREQBUFSIZE];
+ DWORD outputsize;
+ DWORD numaddresses,i;
+ SOCKET_ADDRESS_LIST *addrlist;
+
+ if (WSAIoctl(rtpsock,SIO_ADDRESS_LIST_QUERY,NULL,0,&buffer,RTPUDPV6TRANS_IFREQBUFSIZE,&outputsize,NULL,NULL))
+ return false;
+
+ addrlist = (SOCKET_ADDRESS_LIST *)buffer;
+ numaddresses = addrlist->iAddressCount;
+ for (i = 0 ; i < numaddresses ; i++)
+ {
+ SOCKET_ADDRESS *sockaddr = &(addrlist->Address[i]);
+ if (sockaddr->iSockaddrLength == sizeof(struct sockaddr_in6)) // IPv6 address
+ {
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *)sockaddr->lpSockaddr;
+
+ localIPs.push_back(addr->sin6_addr);
+ }
+ }
+
+ if (localIPs.empty())
+ return false;
+ return true;
+}
+
+#else
+
+#ifdef RTP_SUPPORT_IFADDRS
+
+bool RTPUDPv6Transmitter::GetLocalIPList_Interfaces()
+{
+ struct ifaddrs *addrs,*tmp;
+
+ getifaddrs(&addrs);
+ tmp = addrs;
+
+ while (tmp != 0)
+ {
+ if (tmp->ifa_addr != 0 && tmp->ifa_addr->sa_family == AF_INET6)
+ {
+ struct sockaddr_in6 *inaddr = (struct sockaddr_in6 *)tmp->ifa_addr;
+ localIPs.push_back(inaddr->sin6_addr);
+ }
+ tmp = tmp->ifa_next;
+ }
+
+ freeifaddrs(addrs);
+
+ if (localIPs.empty())
+ return false;
+ return true;
+}
+
+#else
+
+bool RTPUDPv6Transmitter::GetLocalIPList_Interfaces()
+{
+ return false;
+}
+
+#endif // RTP_SUPPORT_IFADDRS
+
+#endif // WIN32
+
+void RTPUDPv6Transmitter::GetLocalIPList_DNS()
+{
+ int status;
+ char name[1024];
+
+ gethostname(name,1023);
+ name[1023] = 0;
+
+ struct addrinfo hints;
+ struct addrinfo *res,*tmp;
+
+ memset(&hints,0,sizeof(struct addrinfo));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = 0;
+ hints.ai_protocol = 0;
+
+ if ((status = getaddrinfo(name,0,&hints,&res)) != 0)
+ return;
+
+ tmp = res;
+ while (tmp != 0)
+ {
+ if (tmp->ai_family == AF_INET6)
+ {
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *)(tmp->ai_addr);
+ localIPs.push_back(addr->sin6_addr);
+ }
+ tmp = tmp->ai_next;
+ }
+
+ freeaddrinfo(res);
+}
+
+
+void RTPUDPv6Transmitter::AbortWaitInternal()
+{
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ send(abortdesc[1],"*",1,0);
+#else
+ write(abortdesc[1],"*",1);
+#endif // WIN32
+}
+
+
+void RTPUDPv6Transmitter::AddLoopbackAddress()
+{
+ std::list<in6_addr>::const_iterator it;
+ bool found = false;
+
+ for (it = localIPs.begin() ; !found && it != localIPs.end() ; it++)
+ {
+ if ((*it) == in6addr_loopback)
+ found = true;
+ }
+
+ if (!found)
+ localIPs.push_back(in6addr_loopback);
+}
+
+#ifdef RTPDEBUG
+void RTPUDPv6Transmitter::Dump()
+{
+ if (!init)
+ std::cout << "Not initialized" << std::endl;
+ else
+ {
+ MAINMUTEX_LOCK
+
+ if (!created)
+ std::cout << "Not created" << std::endl;
+ else
+ {
+ char str[48];
+ in6_addr ip;
+ uint16_t ip16[8];
+ std::list<in6_addr>::const_iterator it;
+ int i,j;
+
+ std::cout << "Portbase: " << portbase << std::endl;
+ std::cout << "RTP socket descriptor: " << rtpsock << std::endl;
+ std::cout << "RTCP socket descriptor: " << rtcpsock << std::endl;
+ ip = bindIP;
+ for (i = 0,j = 0 ; j < 8 ; j++,i += 2) { ip16[j] = (((uint16_t)ip.s6_addr[i])<<8); ip16[j] |= ((uint16_t)ip.s6_addr[i+1]); }
+ RTP_SNPRINTF(str,48,"%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",(int)ip16[0],(int)ip16[1],(int)ip16[2],(int)ip16[3],(int)ip16[4],(int)ip16[5],(int)ip16[6],(int)ip16[7]);
+ std::cout << "Bind IP address: " << str << std::endl;
+ std::Cout << "Multicast interface index: " << mcastifidx << std::endl;
+ std::cout << "Local IP addresses:" << std::endl;
+ for (it = localIPs.begin() ; it != localIPs.end() ; it++)
+ {
+ ip = (*it);
+ for (i = 0,j = 0 ; j < 8 ; j++,i += 2) { ip16[j] = (((uint16_t)ip.s6_addr[i])<<8); ip16[j] |= ((uint16_t)ip.s6_addr[i+1]); }
+ RTP_SNPRINTF(str,48,"%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",(int)ip16[0],(int)ip16[1],(int)ip16[2],(int)ip16[3],(int)ip16[4],(int)ip16[5],(int)ip16[6],(int)ip16[7]);
+ std::cout << " " << str << std::endl;
+ }
+ std::cout << "Multicast TTL: " << (int)multicastTTL << std::endl;
+ std::cout << "Receive mode: ";
+ switch (receivemode)
+ {
+ case RTPTransmitter::AcceptAll:
+ std::cout << "Accept all";
+ break;
+ case RTPTransmitter::AcceptSome:
+ std::cout << "Accept some";
+ break;
+ case RTPTransmitter::IgnoreSome:
+ std::cout << "Ignore some";
+ }
+ std::cout << std::endl;
+ if (receivemode != RTPTransmitter::AcceptAll)
+ {
+ acceptignoreinfo.GotoFirstElement();
+ while(acceptignoreinfo.HasCurrentElement())
+ {
+ ip = acceptignoreinfo.GetCurrentKey();
+ for (i = 0,j = 0 ; j < 8 ; j++,i += 2) { ip16[j] = (((uint16_t)ip.s6_addr[i])<<8); ip16[j] |= ((uint16_t)ip.s6_addr[i+1]); }
+ RTP_SNPRINTF(str,48,"%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",(int)ip16[0],(int)ip16[1],(int)ip16[2],(int)ip16[3],(int)ip16[4],(int)ip16[5],(int)ip16[6],(int)ip16[7]);
+ PortInfo *pinfo = acceptignoreinfo.GetCurrentElement();
+ std::cout << " " << str << ": ";
+ if (pinfo->all)
+ {
+ std::cout << "All ports";
+ if (!pinfo->portlist.empty())
+ std::cout << ", except ";
+ }
+
+ std::list<uint16_t>::const_iterator it;
+
+ for (it = pinfo->portlist.begin() ; it != pinfo->portlist.end() ; )
+ {
+ std::cout << (*it);
+ it++;
+ if (it != pinfo->portlist.end())
+ std::cout << ", ";
+ }
+ std::cout << std::endl;
+ }
+ }
+
+ std::cout << "Local host name: ";
+ if (localhostname == 0)
+ std::cout << "Not set";
+ else
+ std::cout << localhostname;
+ std::cout << std::endl;
+
+ std::cout << "List of destinations: ";
+ destinations.GotoFirstElement();
+ if (destinations.HasCurrentElement())
+ {
+ std::cout << std::endl;
+ do
+ {
+ std::cout << " " << destinations.GetCurrentElement().GetDestinationString() << std::endl;
+ destinations.GotoNextElement();
+ } while (destinations.HasCurrentElement());
+ }
+ else
+ std::cout << "Empty" << std::endl;
+
+ std::cout << "Supports multicasting: " << ((supportsmulticasting)?"Yes":"No") << std::endl;
+#ifdef RTP_SUPPORT_IPV6MULTICAST
+ std::cout << "List of multicast groups: ";
+ multicastgroups.GotoFirstElement();
+ if (multicastgroups.HasCurrentElement())
+ {
+ std::cout << std::endl;
+ do
+ {
+ ip = multicastgroups.GetCurrentElement();
+ for (i = 0,j = 0 ; j < 8 ; j++,i += 2) { ip16[j] = (((uint16_t)ip.s6_addr[i])<<8); ip16[j] |= ((uint16_t)ip.s6_addr[i+1]); }
+ RTP_SNPRINTF(str,48,"%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",(int)ip16[0],(int)ip16[1],(int)ip16[2],(int)ip16[3],(int)ip16[4],(int)ip16[5],(int)ip16[6],(int)ip16[7]);
+ std::cout << " " << str << std::endl;
+ multicastgroups.GotoNextElement();
+ } while (multicastgroups.HasCurrentElement());
+ }
+ else
+ std::cout << "Empty" << std::endl;
+#endif // RTP_SUPPORT_IPV6MULTICAST
+
+ std::cout << "Number of raw packets in queue: " << rawpacketlist.size() << std::endl;
+ std::cout << "Maximum allowed packet size: " << maxpacksize << std::endl;
+ }
+
+ MAINMUTEX_UNLOCK
+ }
+
+}
+#endif // RTPDEBUG
+
+#endif // RTP_SUPPORT_IPV6
+
diff --git a/src/rtpudpv6transmitter.h b/src/rtpudpv6transmitter.h
new file mode 100644
index 0000000..41f6335
--- /dev/null
+++ b/src/rtpudpv6transmitter.h
@@ -0,0 +1,313 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+/**
+ * \file rtpudpv6transmitter.h
+ */
+
+#ifndef RTPUDPV6TRANSMITTER_H
+
+#define RTPUDPV6TRANSMITTER_H
+
+#include "rtpconfig.h"
+
+#ifdef RTP_SUPPORT_IPV6
+
+#include "rtptransmitter.h"
+#include "rtpipv6destination.h"
+#include "rtphashtable.h"
+#include "rtpkeyhashtable.h"
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ #include <netinet/in.h>
+#endif // WIN32
+#include <string.h>
+#include <list>
+
+#ifdef RTP_SUPPORT_THREAD
+ #include <jmutex.h>
+#endif // RTP_SUPPORT_THREAD
+
+#define RTPUDPV6TRANS_HASHSIZE 8317
+#define RTPUDPV6TRANS_DEFAULTPORTBASE 5000
+
+#define RTPUDPV6TRANS_RTPRECEIVEBUFFER 32768
+#define RTPUDPV6TRANS_RTCPRECEIVEBUFFER 32768
+#define RTPUDPV6TRANS_RTPTRANSMITBUFFER 32768
+#define RTPUDPV6TRANS_RTCPTRANSMITBUFFER 32768
+
+/** Parameters for the UDP over IPv6 transmitter. */
+class RTPUDPv6TransmissionParams : public RTPTransmissionParams
+{
+public:
+ RTPUDPv6TransmissionParams():RTPTransmissionParams(RTPTransmitter::IPv6UDPProto) { portbase = RTPUDPV6TRANS_DEFAULTPORTBASE; for (int i = 0 ; i < 16 ; i++) bindIP.s6_addr[i] = 0; multicastTTL = 1; mcastifidx = 0; rtpsendbuf = RTPUDPV6TRANS_RTPTRANSMITBUFFER; rtprecvbuf= RTPUDPV6TRANS_RTPRECEIVEBUFFER; rtcpsendbuf = RTPUDPV6TRANS_RTCPTRANSMITBUFFER; rtcprecvbuf = RTPUDPV6TRANS_RTCPRECEIVEBUFFER; }
+
+ /** Sets the IP address which is used to bind the sockets to \c ip. */
+ void SetBindIP(in6_addr ip) { bindIP = ip; }
+
+ /** Sets the multicast interface index. */
+ void SetMulticastInterfaceIndex(unsigned int idx) { mcastifidx = idx; }
+
+ /** Sets the RTP portbase to \c pbase. This has to be an even number. */
+ void SetPortbase(uint16_t pbase) { portbase = pbase; }
+
+ /** Sets the multicast TTL to be used to \c mcastTTL. */
+ void SetMulticastTTL(uint8_t mcastTTL) { multicastTTL = mcastTTL; }
+
+ /** Passes a list of IP addresses which will be used as the local IP addresses. */
+ void SetLocalIPList(std::list<in6_addr> &iplist) { localIPs = iplist; }
+
+ /** Clears the list of local IP addresses.
+ * Clears the list of local IP addresses. An empty list will make the transmission component
+ * itself determine the local IP addresses.
+ */
+ void ClearLocalIPList() { localIPs.clear(); }
+
+ /** Returns the IP address which will be used to bind the sockets. */
+ in6_addr GetBindIP() const { return bindIP; }
+
+ /** Returns the multicast interface index. */
+ unsigned int GetMulticastInterfaceIndex() const { return mcastifidx; }
+
+ /** Returns the RTP portbase which will be used (default is 5000). */
+ uint16_t GetPortbase() const { return portbase; }
+
+ /** Returns the multicast TTL which will be used (default is 1). */
+ uint8_t GetMulticastTTL() const { return multicastTTL; }
+
+ /** Returns the list of local IP addresses. */
+ const std::list<in6_addr> &GetLocalIPList() const { return localIPs; }
+
+ /** Sets the RTP socket's send buffer size. */
+ void SetRTPSendBuffer(int s) { rtpsendbuf = s; }
+
+ /** Sets the RTP socket's receive buffer size. */
+ void SetRTPReceiveBuffer(int s) { rtprecvbuf = s; }
+
+ /** Sets the RTCP socket's send buffer size. */
+ void SetRTCPSendBuffer(int s) { rtcpsendbuf = s; }
+
+ /** Sets the RTCP socket's receive buffer size. */
+ void SetRTCPReceiveBuffer(int s) { rtcprecvbuf = s; }
+
+ /** Returns the RTP socket's send buffer size. */
+ int GetRTPSendBuffer() const { return rtpsendbuf; }
+
+ /** Returns the RTP socket's receive buffer size. */
+ int GetRTPReceiveBuffer() const { return rtprecvbuf; }
+
+ /** Returns the RTCP socket's send buffer size. */
+ int GetRTCPSendBuffer() const { return rtcpsendbuf; }
+
+ /** Returns the RTCP socket's receive buffer size. */
+ int GetRTCPReceiveBuffer() const { return rtcprecvbuf; }
+private:
+ uint16_t portbase;
+ in6_addr bindIP;
+ unsigned int mcastifidx;
+ std::list<in6_addr> localIPs;
+ uint8_t multicastTTL;
+ int rtpsendbuf, rtprecvbuf;
+ int rtcpsendbuf, rtcprecvbuf;
+};
+
+/** Additional information about the UDP over IPv6 transmitter. */
+class RTPUDPv6TransmissionInfo : public RTPTransmissionInfo
+{
+public:
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ RTPUDPv6TransmissionInfo(std::list<in6_addr> iplist,int rtpsock,int rtcpsock) : RTPTransmissionInfo(RTPTransmitter::IPv6UDPProto)
+#else
+ RTPUDPv6TransmissionInfo(std::list<in6_addr> iplist,SOCKET rtpsock,SOCKET rtcpsock) : RTPTransmissionInfo(RTPTransmitter::IPv6UDPProto)
+#endif // WIN32
+ { localIPlist = iplist; rtpsocket = rtpsock; rtcpsocket = rtcpsock; }
+
+ ~RTPUDPv6TransmissionInfo() { }
+
+ /** Returns the list of IPv6 addresses the transmitter considers to be the local IP addresses. */
+ std::list<in6_addr> GetLocalIPList() const { return localIPlist; }
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ /** Returns the socket descriptor used for receiving and transmitting RTP packets. */
+ int GetRTPSocket() const { return rtpsocket; }
+
+ /** Returns the socket descriptor used for receiving and transmitting RTCP packets. */
+ int GetRTCPSocket() const { return rtcpsocket; }
+#else
+ SOCKET GetRTPSocket() const { return rtpsocket; }
+ SOCKET GetRTCPSocket() const { return rtcpsocket; }
+#endif // WIN32
+private:
+ std::list<in6_addr> localIPlist;
+#if ! (defined(WIN32) || defined(_WIN32_WCE))
+ int rtpsocket,rtcpsocket;
+#else
+ SOCKET rtpsocket,rtcpsocket;
+#endif // WIN32
+};
+
+class RTPUDPv6Trans_GetHashIndex_IPv6Dest
+{
+public:
+ static int GetIndex(const RTPIPv6Destination &d) { in6_addr ip = d.GetIP(); return ((((uint32_t)ip.s6_addr[12])<<24)|(((uint32_t)ip.s6_addr[13])<<16)|(((uint32_t)ip.s6_addr[14])<<8)|((uint32_t)ip.s6_addr[15]))%RTPUDPV6TRANS_HASHSIZE; }
+};
+
+class RTPUDPv6Trans_GetHashIndex_in6_addr
+{
+public:
+ static int GetIndex(const in6_addr &ip) { return ((((uint32_t)ip.s6_addr[12])<<24)|(((uint32_t)ip.s6_addr[13])<<16)|(((uint32_t)ip.s6_addr[14])<<8)|((uint32_t)ip.s6_addr[15]))%RTPUDPV6TRANS_HASHSIZE; }
+};
+
+#define RTPUDPV6TRANS_HEADERSIZE (40+8)
+
+/** An UDP over IPv6 transmitter.
+ * This class inherits the RTPTransmitter interface and implements a transmission component
+ * which uses UDP over IPv6 to send and receive RTP and RTCP data. The component's parameters
+ * are described by the class RTPUDPv6TransmissionParams. The functions which have an RTPAddress
+ * argument require an argument of RTPIPv6Address. The GetTransmissionInfo member function
+ * returns an instance of type RTPUDPv6TransmissionInfo.
+ */
+class RTPUDPv6Transmitter : public RTPTransmitter
+{
+public:
+ RTPUDPv6Transmitter(RTPMemoryManager *mgr);
+ ~RTPUDPv6Transmitter();
+
+ int Init(bool treadsafe);
+ int Create(size_t maxpacksize,const RTPTransmissionParams *transparams);
+ void Destroy();
+ RTPTransmissionInfo *GetTransmissionInfo();
+
+ int GetLocalHostName(uint8_t *buffer,size_t *bufferlength);
+ bool ComesFromThisTransmitter(const RTPAddress *addr);
+ size_t GetHeaderOverhead() { return RTPUDPV6TRANS_HEADERSIZE; }
+
+ int Poll();
+ int WaitForIncomingData(const RTPTime &delay,bool *dataavailable = 0);
+ int AbortWait();
+
+ int SendRTPData(const void *data,size_t len);
+ int SendRTCPData(const void *data,size_t len);
+
+ int AddDestination(const RTPAddress &addr);
+ int DeleteDestination(const RTPAddress &addr);
+ void ClearDestinations();
+
+ bool SupportsMulticasting();
+ int JoinMulticastGroup(const RTPAddress &addr);
+ int LeaveMulticastGroup(const RTPAddress &addr);
+ void LeaveAllMulticastGroups();
+
+ int SetReceiveMode(RTPTransmitter::ReceiveMode m);
+ int AddToIgnoreList(const RTPAddress &addr);
+ int DeleteFromIgnoreList(const RTPAddress &addr);
+ void ClearIgnoreList();
+ int AddToAcceptList(const RTPAddress &addr);
+ int DeleteFromAcceptList(const RTPAddress &addr);
+ void ClearAcceptList();
+ int SetMaximumPacketSize(size_t s);
+
+ bool NewDataAvailable();
+ RTPRawPacket *GetNextPacket();
+#ifdef RTPDEBUG
+ void Dump();
+#endif // RTPDEBUG
+private:
+ int CreateLocalIPList();
+ bool GetLocalIPList_Interfaces();
+ void GetLocalIPList_DNS();
+ void AddLoopbackAddress();
+ void FlushPackets();
+ int PollSocket(bool rtp);
+ int ProcessAddAcceptIgnoreEntry(in6_addr ip,uint16_t port);
+ int ProcessDeleteAcceptIgnoreEntry(in6_addr ip,uint16_t port);
+#ifdef RTP_SUPPORT_IPV6MULTICAST
+ bool SetMulticastTTL(uint8_t ttl);
+#endif // RTP_SUPPORT_IPV6MULTICAST
+ bool ShouldAcceptData(in6_addr srcip,uint16_t srcport);
+ void ClearAcceptIgnoreInfo();
+
+ bool init;
+ bool created;
+ bool waitingfordata;
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ SOCKET rtpsock,rtcpsock;
+#else // not using winsock
+ int rtpsock,rtcpsock;
+#endif // WIN32
+ in6_addr bindIP;
+ unsigned int mcastifidx;
+ std::list<in6_addr> localIPs;
+ uint16_t portbase;
+ uint8_t multicastTTL;
+ RTPTransmitter::ReceiveMode receivemode;
+
+ uint8_t *localhostname;
+ size_t localhostnamelength;
+
+ RTPHashTable<const RTPIPv6Destination,RTPUDPv6Trans_GetHashIndex_IPv6Dest,RTPUDPV6TRANS_HASHSIZE> destinations;
+#ifdef RTP_SUPPORT_IPV6MULTICAST
+ RTPHashTable<const in6_addr,RTPUDPv6Trans_GetHashIndex_in6_addr,RTPUDPV6TRANS_HASHSIZE> multicastgroups;
+#endif // RTP_SUPPORT_IPV6MULTICAST
+ std::list<RTPRawPacket*> rawpacketlist;
+
+ bool supportsmulticasting;
+ size_t maxpacksize;
+
+ class PortInfo
+ {
+ public:
+ PortInfo() { all = false; }
+
+ bool all;
+ std::list<uint16_t> portlist;
+ };
+
+ RTPKeyHashTable<const in6_addr,PortInfo*,RTPUDPv6Trans_GetHashIndex_in6_addr,RTPUDPV6TRANS_HASHSIZE> acceptignoreinfo;
+
+ // notification descriptors for AbortWait (0 is for reading, 1 for writing)
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ SOCKET abortdesc[2];
+#else
+ int abortdesc[2];
+#endif // WIN32
+ int CreateAbortDescriptors();
+ void DestroyAbortDescriptors();
+ void AbortWaitInternal();
+#ifdef RTP_SUPPORT_THREAD
+ JMutex mainmutex,waitmutex;
+ int threadsafe;
+#endif // RTP_SUPPORT_THREAD
+};
+
+#endif // RTP_SUPPORT_IPV6
+
+#endif // RTPUDPV6TRANSMITTER_H
+