Commit 32e7b8fd authored by Yann Diorcet's avatar Yann Diorcet
Browse files

Merge branch 'master' of git.linphone.org:mediastreamer2

parents bffd68be 37474c87
......@@ -166,7 +166,7 @@ AC_DEFUN([MS_CHECK_VIDEO],[
fi
AC_ARG_ENABLE(xv,
[ --enable-xv Enable xv supportl],
[ --enable-xv Enable xv support],
[case "${enableval}" in
yes) enable_xv=true ;;
no) enable_xv=false ;;
......@@ -183,6 +183,25 @@ AC_DEFUN([MS_CHECK_VIDEO],[
AC_MSG_ERROR([No X video output API found. Please install X11+Xv headers.])
fi
fi
AC_ARG_ENABLE(gl,
[ --enable-gl Enable GL rendering support (require glx and glew)],
[case "${enableval}" in
yes) enable_gl=true ;;
no) enable_gl=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-gl) ;;
esac],[enable_gl=false])
if test "$enable_gl" = "true"; then
AC_CHECK_HEADERS(GL/gl.h,[] ,[enable_gl=false])
AC_CHECK_HEADERS(GL/glx.h,[] ,[enable_gl=false],[
#include <GL/glx.h>
])
if test "$enable_gl" = "false" ; then
AC_MSG_ERROR([No GL/GLX API found. Please install GL and GLX headers.])
fi
PKG_CHECK_MODULES(GLEW,[glew >= 1.6])
AC_CHECK_HEADERS(X11/Xlib.h)
fi
fi
AC_ARG_ENABLE(theora,
......@@ -241,6 +260,13 @@ AC_DEFUN([MS_CHECK_VIDEO],[
if test "$ios_found" = "yes" ; then
LIBS="$LIBS -framework AVFoundation -framework CoreVideo -framework CoreMedia"
fi
if test "$enable_gl" = "true"; then
VIDEO_LIBS="$VIDEO_LIBS -lGL -lGLEW"
VIDEO_CFLAGS="$VIDEO_CFLAGS -DHAVE_GL"
fi
if test "$enable_xv" = "true"; then
VIDEO_CFLAGS="$VIDEO_CFLAGS -DHAVE_XV"
fi
fi
AC_SUBST(VIDEO_CFLAGS)
......
......@@ -544,6 +544,7 @@ AM_CONDITIONAL(BUILD_WIN32_WCE, test "$mingw32ce_found" = "yes")
AM_CONDITIONAL(BUILD_FFMPEG, test "$ffmpeg" = "true")
AM_CONDITIONAL(BUILD_SDL,test "$sdl_found" = "true" )
AM_CONDITIONAL(BUILD_X11_XV, test "$enable_xv" = "true" )
AM_CONDITIONAL(BUILD_X11_GL, test "$enable_gl" = "true" )
dnl *********************************************
dnl setup oRTP dependency
......
......@@ -132,7 +132,8 @@ typedef enum MSFilterId{
MS_AAL2_G726_16_DEC_ID,
MS_L16_ENC_ID,
MS_L16_DEC_ID,
MS_OSX_GL_DISPLAY_ID
MS_OSX_GL_DISPLAY_ID,
MS_GLXVIDEO_ID
} MSFilterId;
......
......@@ -61,6 +61,7 @@ struct _AudioStream
MSFilter *read_resampler;
MSFilter *write_resampler;
MSFilter *equalizer;
MSFilter *dummy;
uint64_t last_packet_count;
time_t last_packet_time;
EchoLimiterType el_type; /*use echo limiter: two MSVolume, measured input level controlling local output level*/
......@@ -157,6 +158,11 @@ MS2_PUBLIC void audio_stream_play_received_dtmfs(AudioStream *st, bool_t yesno);
* @returns a new AudioStream.
**/
MS2_PUBLIC AudioStream *audio_stream_new(int locport, bool_t ipv6);
MS2_PUBLIC void audio_stream_prepare_sound(AudioStream *st, MSSndCard *playcard, MSSndCard *captcard);
MS2_PUBLIC void audio_stream_unprepare_sound(AudioStream *st);
MS2_PUBLIC bool_t audio_stream_started(AudioStream *stream);
/**
* Starts an audio stream from local soundcards.
*
......
......@@ -58,9 +58,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MS_VIDEO_DISPLAY_SHOW_VIDEO \
MS_FILTER_METHOD(MSFilterVideoDisplayInterface,9,int)
#define MS_VIDEO_DISPLAY_ZOOM \
MS_FILTER_METHOD(MSFilterVideoDisplayInterface,10,int[4])
/**Specifiy device orientation from portrait */
#define MS_VIDEO_DISPLAY_SET_DEVICE_ORIENTATION \
MS_FILTER_METHOD(MSFilterVideoDisplayInterface,10,int)
MS_FILTER_METHOD(MSFilterVideoDisplayInterface,11,int)
/**
* Interface definitions for players
......@@ -129,6 +132,8 @@ typedef enum _MSPlayerState MSPlayerState;
MS_FILTER_EVENT_NO_ARG(MSFilterVideoDecoderInterface,0)
#define MS_VIDEO_DECODER_FIRST_IMAGE_DECODED \
MS_FILTER_EVENT_NO_ARG(MSFilterVideoDecoderInterface,1)
#define MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION \
MS_FILTER_METHOD_NO_ARG(MSFilterVideoDecoderInterface, 0)
/** Interface definitions for video capture */
#define MS_VIDEO_CAPTURE_SET_DEVICE_ORIENTATION \
......
......@@ -131,6 +131,7 @@ struct _MSSndCard{
char *id;
unsigned int capabilities;
void *data;
int preferred_sample_rate;
};
/**
......@@ -425,6 +426,26 @@ MS2_PUBLIC int ms_snd_card_set_control(MSSndCard *obj, MSSndCardControlElem e, i
*/
MS2_PUBLIC int ms_snd_card_get_control(MSSndCard *obj, MSSndCardControlElem e);
/**
* Get preferred sample rate
*
* @param obj A sound card object.
*
* Returns: return sample rate in khz
*/
MS2_PUBLIC int ms_snd_card_get_preferred_sample_rate(const MSSndCard *obj);
/**
* set preferred sample rate. The underlying card will try to avoid any resampling for this samplerate.
*
* @param obj A sound card object.
* @param rate sampling rate.
*
* Returns: 0 if successfull, <0 otherwise.
*/
MS2_PUBLIC int ms_snd_card_set_preferred_sample_rate(MSSndCard *obj,int rate);
/**
* Create a alsa card with user supplied pcm name and mixer name.
* @param pcmdev The pcm device name following alsa conventions (ex: plughw:0)
......
......@@ -82,6 +82,13 @@ struct _MSTicker
typedef struct _MSTicker MSTicker;
struct _MSTickerParams{
MSTickerPrio prio;
const char *name;
};
typedef struct _MSTickerParams MSTickerParams;
#ifdef __cplusplus
extern "C"{
#endif
......@@ -95,13 +102,21 @@ extern "C"{
*/
MS2_PUBLIC MSTicker *ms_ticker_new(void);
/**
* Create a ticker that will be used to start
* and stop a graph.
*
* Returns: MSTicker * if successfull, NULL otherwise.
*/
MS2_PUBLIC MSTicker *ms_ticker_new_with_params(const MSTickerParams *params);
/**
* Set a name to the ticker (used for logging)
**/
MS2_PUBLIC void ms_ticker_set_name(MSTicker *ticker, const char *name);
/**
* Set priority to the ticker
* Deprecated: Set priority to the ticker
**/
MS2_PUBLIC void ms_ticker_set_priority(MSTicker *ticker, MSTickerPrio prio);
......@@ -117,6 +132,18 @@ MS2_PUBLIC void ms_ticker_set_priority(MSTicker *ticker, MSTickerPrio prio);
*/
MS2_PUBLIC int ms_ticker_attach(MSTicker *ticker,MSFilter *f);
/**
* Attach a chain of filters to a ticker.
* The processing chain will be executed until ms_ticker_detach
* will be called.
* This variadic can be used to attach multiple chains in a single call. The argument list MUST be NULL terminated.
*
* @param ticker A #MSTicker object.
* @param f A #MSFilter object.
*
* Returns: 0 if successfull, -1 otherwise.
*/
MS2_PUBLIC int ms_ticker_attach_multiple(MSTicker *ticker,MSFilter *f,...);
/**
* Dettach a chain of filters to a ticker.
* The processing chain will no more be executed.
......
......@@ -319,11 +319,11 @@ MS2_PUBLIC bool_t ms_video_capture_new_frame(MSFrameRateController* ctrl, uint32
struct _MSAverageFPS {
unsigned int last_frame_time, last_print_time;
float mean_inter_frame;
float expected_fps;
const char* context;
};
typedef struct _MSAverageFPS MSAverageFPS;
MS2_PUBLIC void ms_video_init_average_fps(MSAverageFPS* afps, float expectedFps);
MS2_PUBLIC void ms_video_update_average_fps(MSAverageFPS* afps, uint32_t current_time);
MS2_PUBLIC void ms_video_init_average_fps(MSAverageFPS* afps, const char* context);
MS2_PUBLIC bool_t ms_video_update_average_fps(MSAverageFPS* afps, uint32_t current_time);
#ifdef __cplusplus
}
......
......@@ -20,6 +20,8 @@ package org.linphone.mediastream;
import org.linphone.mediastream.video.capture.hwconf.Hacks;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
/**
......@@ -51,6 +53,11 @@ public class Version {
// 8; // 2.2
// 7; // 2.1
public static boolean isXLargeScreen(Context context)
{
return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
}
public static final boolean sdkAboveOrEqual(int value) {
return buildVersion >= value;
}
......@@ -75,7 +82,7 @@ public class Version {
return hasNeon;
}
public static boolean isVideoCapable() {
return !Version.sdkStrictlyBelow(5) && Version.hasNeon() && Hacks.hasCamera();
return !Version.sdkStrictlyBelow(5) && Hacks.hasCamera();
}
private static Boolean sCacheHasZrtp;
......
......@@ -13,11 +13,11 @@ EXTRA_DIST= winsnd2.c winsnd.c winvideo.c \
winvideods.c wincevideods.c dxfilter.h dxfilter.cpp \
msfileplayer_win.c msfilerec_win.c winsndds.cpp nowebcamCIF.jpg winsnd3.c vfw-missing.h \
winvideo2.c msjava.c $(ANDROID_SRC_FILES) \
$(GITVERSION_FILE)
$(GITVERSION_FILE) yuv2rgb.fs yuv2rgb.vs
BUILT_SOURCES=alldescs.h $(GITVERSION_FILE)
BUILT_SOURCES=alldescs.h $(GITVERSION_FILE) yuv2rgb.fs.h yuv2rgb.vs.h
CLEANFILES=alldescs.h filterdescs.txt $(GITVERSION_FILE)
CLEANFILES=alldescs.h filterdescs.txt $(GITVERSION_FILE) yuv2rgb.fs.h yuv2rgb.vs.h
INCLUDES=-I$(top_srcdir)/include/
......@@ -114,7 +114,7 @@ libmediastreamer_la_SOURCES+=macsnd.c
endif
if BUILD_IOSIOUNIT
libmediastreamer_la_SOURCES+=msiounit.c
libmediastreamer_la_SOURCES+=msiounit.m
endif
if BUILD_MACAQSND
......@@ -128,11 +128,13 @@ endif
if BUILD_VIDEO
if BUILD_MACOSX
libmediastreamer_la_SOURCES+=qtcapture.m msosxdisplay.m shaders.c shaders.h opengles_display.c opengles_display.h yuv2rgb.vs.h yuv2rgb.fs.h
libmediastreamer_la_SOURCES+=qtcapture.m msosxdisplay.m shaders.c shaders.h opengles_display.c opengles_display.h
nodist_libmediastreamer_la_SOURCES = yuv2rgb.fs.h yuv2rgb.fs.h
endif
if BUILD_IOS
libmediastreamer_la_SOURCES+=scaler.c iosdisplay.m ioscapture.m shaders.c shaders.h opengles_display.c opengles_display.h yuv2rgb.vs.h yuv2rgb.fs.h
libmediastreamer_la_SOURCES+=scaler.c iosdisplay.m ioscapture.m shaders.c shaders.h opengles_display.c opengles_display.h
nodist_libmediastreamer_la_SOURCES = yuv2rgb.fs.h yuv2rgb.fs.h
endif
if BUILD_V4L1
libmediastreamer_la_SOURCES+=msv4l.c
......@@ -170,11 +172,16 @@ if BUILD_X11_XV
libmediastreamer_la_SOURCES+=x11video.c
endif
if BUILD_X11_GL
libmediastreamer_la_SOURCES+=glxvideo.c opengles_display.c shaders.c
endif
libmediastreamer_la_SOURCES+= rfc2429.h \
pixconv.c \
sizeconv.c \
msvideo.c \
msvideo_neon.c \
msvideo_neon.c \
msvideo_neon.h \
rfc3984.c \
mire.c \
extdisplay.c \
......@@ -213,7 +220,8 @@ endif
if BUILD_VIDEO
libmediastreamer_la_LIBADD+= $(VIDEO_LIBS) \
$(THEORA_LIBS)
$(THEORA_LIBS) \
$(GLEW_LIBS)
if BUILD_IOS
libmediastreamer_la_LDFLAGS+= -framework CoreGraphics
endif
......@@ -251,7 +259,7 @@ AM_CXXFLAGS= $(ORTP_CFLAGS) \
DEFS=@DEFS@ -DPACKAGE_PLUGINS_DIR=\"$(PACKAGE_PLUGINS_DIR)\" -DLOCALEDIR=\"$(localedir)\" -DMS2_INTERNAL
if BUILD_VIDEO
AM_CFLAGS+=$(VIDEO_CFLAGS)
AM_CFLAGS+=$(VIDEO_CFLAGS) $(GLEW_CFLAGS)
endif
if BUILD_VP8
......@@ -280,6 +288,16 @@ make_gitversion_h:
$(GITVERSION_FILE): make_gitversion_h
yuv2rgb.fs.h: yuv2rgb.fs
builddir=`pwd` && \
cd $(top_srcdir)/src && \
xxd -i yuv2rgb.fs | sed s/}\;/,0x00}\;/ > $$builddir/yuv2rgb.fs.h
yuv2rgb.vs.h: yuv2rgb.vs
builddir=`pwd` && \
cd $(top_srcdir)/src && \
xxd -i yuv2rgb.vs | sed s/}\;/,0x00}\;/ > $$builddir/yuv2rgb.vs.h
......
......@@ -76,13 +76,40 @@ static float gain_volume_out=1.0;
static bool gain_changed_in = true;
static bool gain_changed_out = true;
const char* aq_format_error(OSStatus status) {
switch (status) {
case kAudioQueueErr_InvalidBuffer: return "kAudioQueueErr_InvalidBuffer";
case kAudioQueueErr_BufferEmpty: return"kAudioQueueErr_BufferEmpty";
case kAudioQueueErr_DisposalPending: return"kAudioQueueErr_DisposalPending";
case kAudioQueueErr_InvalidProperty: return"kAudioQueueErr_InvalidProperty";
case kAudioQueueErr_InvalidPropertySize: return"kAudioQueueErr_InvalidPropertySize";
case kAudioQueueErr_InvalidParameter: return"kAudioQueueErr_InvalidParameter";
case kAudioQueueErr_CannotStart: return"kAudioQueueErr_CannotStart";
case kAudioQueueErr_InvalidDevice: return"kAudioQueueErr_InvalidDevice";
case kAudioQueueErr_BufferInQueue: return"kAudioQueueErr_BufferInQueue";
case kAudioQueueErr_InvalidRunState: return"kAudioQueueErr_InvalidRunState";
case kAudioQueueErr_InvalidQueueType: return"kAudioQueueErr_InvalidQueueType";
case kAudioQueueErr_Permissions: return"kAudioQueueErr_Permissions";
case kAudioQueueErr_InvalidPropertyValue: return"kAudioQueueErr_InvalidPropertyValue";
case kAudioQueueErr_PrimeTimedOut: return"kAudioQueueErr_PrimeTimedOut";
case kAudioQueueErr_CodecNotFound: return"kAudioQueueErr_CodecNotFound";
case kAudioQueueErr_InvalidCodecAccess: return"kAudioQueueErr_InvalidCodecAccess";
case kAudioQueueErr_QueueInvalidated: return"kAudioQueueErr_QueueInvalidated";
case kAudioQueueErr_RecordUnderrun: return"kAudioQueueErr_RecordUnderrun";
case kAudioQueueErr_EnqueueDuringReset: return"kAudioQueueErr_EnqueueDuringReset";
case kAudioQueueErr_InvalidOfflineMode: return"kAudioQueueErr_InvalidOfflineMode";
default:
return "unkown error code";
}
}
#ifdef __ios
#define CFStringRef void *
#define CFRelease(A) {}
#define CFStringGetCString(A, B, LEN, encoding) {}
#define CFStringCreateCopy(A, B) NULL
#define check_aqresult(aq,method) \
if (aq!=0) ms_error("AudioQueue error for %s: ret=%li",method,aq)
if (aq!=0) ms_error("AudioQueue error for %s: ret=%s",method,aq_format_error(aq))
#endif
typedef struct AQData {
......@@ -734,10 +761,11 @@ static void aq_start_r(MSFilter * f)
setupRead(f);
aqresult = AudioQueueStart(d->readQueue, NULL); // start time. NULL means ASAP.
if (aqresult != noErr) {
ms_error("AudioQueueStart -read- %ld", aqresult);
check_aqresult(aqresult,"AudioQueueStart - read");
if (aqresult == noErr) {
d->read_started = TRUE;
}
d->read_started = TRUE;
}
}
......@@ -882,7 +910,7 @@ static void aq_put(MSFilter * f, mblk_t * m)
(d->writeBufferByteSize * d->writeAudioFormat.mSampleRate / 1) /
d->devicewriteFormat.mSampleRate /
d->devicewriteFormat.mChannelsPerFrame;
if (d->write_started == FALSE && d->bufferizer->size >= len) {
if (d->write_started == FALSE && d->bufferizer->size >= len && d->curWriteBuffer<4) {
AudioQueueBufferRef curbuf = d->writeBuffers[d->curWriteBuffer];
#if 0
OSStatus err;
......@@ -914,10 +942,11 @@ static void aq_put(MSFilter * f, mblk_t * m)
OSStatus err;
err = AudioQueueStart(d->writeQueue, NULL // start time. NULL means ASAP.
);
if (err != noErr) {
ms_error("AudioQueueStart -write- %ld", err);
}
d->write_started = TRUE;
check_aqresult(err, "AudioQueueStart -write-");
if (err == noErr) {
d->write_started = TRUE;
}
}
}
......
......@@ -71,6 +71,7 @@ void audio_stream_free(AudioStream *stream)
if (stream->read_resampler!=NULL) ms_filter_destroy(stream->read_resampler);
if (stream->write_resampler!=NULL) ms_filter_destroy(stream->write_resampler);
if (stream->dtmfgen_rtp!=NULL) ms_filter_destroy(stream->dtmfgen_rtp);
if (stream->dummy) ms_filter_destroy(stream->dummy);
if (stream->rc) ms_bitrate_controller_destroy(stream->rc);
if (stream->qi) ms_quality_indicator_destroy(stream->qi);
ms_free(stream);
......@@ -284,6 +285,50 @@ static void payload_type_changed(RtpSession *session, unsigned long data){
static mblk_t* audio_stream_payload_picker(MSRtpPayloadPickerContext* context,unsigned int sequence_number) {
return rtp_session_pick_with_cseq(((AudioStream*)(context->filter_graph_manager))->session, sequence_number);
}
static void start_ticker(AudioStream *stream){
MSTickerParams params={0};
params.name="Audio MSTicker";
params.prio=__ms_get_default_prio(FALSE);
stream->ticker=ms_ticker_new_with_params(&params);
}
static void stop_preload_graph(AudioStream *stream){
ms_ticker_detach(stream->ticker,stream->dummy);
ms_filter_unlink(stream->dummy,0,stream->soundwrite,0);
ms_filter_destroy(stream->dummy);
stream->dummy=NULL;
}
bool_t audio_stream_started(AudioStream *stream){
return stream->start_time!=0;
}
void audio_stream_prepare_sound(AudioStream *stream, MSSndCard *playcard, MSSndCard *captcard){
#ifdef __ios
if (captcard && playcard){
stream->soundread=ms_snd_card_create_reader(captcard);
stream->soundwrite=ms_snd_card_create_writer(playcard);
stream->dummy=ms_filter_new(MS_FILE_PLAYER_ID);
ms_filter_link(stream->dummy,0,stream->soundwrite,0);
start_ticker(stream);
ms_ticker_attach(stream->ticker,stream->dummy);
}
#endif
}
void audio_stream_unprepare_sound(AudioStream *stream){
#ifdef __ios
if (stream->dummy){
stop_preload_graph(stream);
ms_filter_destroy(stream->soundread);
stream->soundread=NULL;
ms_filter_destroy(stream->soundwrite);
stream->soundwrite=NULL;
}
#endif
}
int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char *remip,int remport,
int rem_rtcp_port, int payload,int jitt_comp, const char *infile, const char *outfile,
MSSndCard *playcard, MSSndCard *captcard, bool_t use_ec)
......@@ -313,14 +358,18 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char
rtp_session_signal_connect(rtps,"telephone-event",(RtpCallback)on_dtmf_received,(unsigned long)stream);
rtp_session_signal_connect(rtps,"payload_type_changed",(RtpCallback)payload_type_changed,(unsigned long)stream);
/* creates the local part */
if (captcard!=NULL) stream->soundread=ms_snd_card_create_reader(captcard);
else {
if (captcard!=NULL){
if (stream->soundread==NULL)
stream->soundread=ms_snd_card_create_reader(captcard);
}else {
stream->soundread=ms_filter_new(MS_FILE_PLAYER_ID);
stream->read_resampler=ms_filter_new(MS_RESAMPLE_ID);
if (infile!=NULL) audio_stream_play(stream,infile);
}
if (playcard!=NULL) stream->soundwrite=ms_snd_card_create_writer(playcard);
else {
if (playcard!=NULL) {
if (stream->soundwrite==NULL)
stream->soundwrite=ms_snd_card_create_writer(playcard);
}else {
stream->soundwrite=ms_filter_new(MS_FILE_REC_ID);
if (outfile!=NULL) audio_stream_record(stream,outfile);
}
......@@ -427,6 +476,13 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char
}
stream->qi=ms_quality_indicator_new(stream->session);
/* create ticker */
if (stream->ticker==NULL) start_ticker(stream);
else{
/*we were using the dummy preload graph, destroy it*/
stop_preload_graph(stream);
}
/* and then connect all */
/* tip: draw yourself the picture if you don't understand */
......@@ -459,12 +515,11 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char
ms_connection_helper_link(&h,stream->write_resampler,0,0);
ms_connection_helper_link(&h,stream->soundwrite,0,-1);
/* create ticker */
stream->ticker=ms_ticker_new();
ms_ticker_set_name(stream->ticker,"Audio MSTicker");
ms_ticker_set_priority(stream->ticker,__ms_get_default_prio(FALSE));
ms_ticker_attach(stream->ticker,stream->soundread);
ms_ticker_attach(stream->ticker,stream->rtprecv);
/*to make sure all preprocess are done before befre processing audio*/
ms_ticker_attach_multiple( stream->ticker
,stream->soundread
,stream->rtprecv
,NULL);
stream->start_time=ms_time(NULL);
stream->is_beginning=TRUE;
......@@ -660,40 +715,45 @@ void audio_stream_stop(AudioStream * stream)
{
if (stream->ticker){
MSConnectionHelper h;
ms_ticker_detach(stream->ticker,stream->soundread);
ms_ticker_detach(stream->ticker,stream->rtprecv);
rtp_stats_display(rtp_session_get_stats(stream->session),"Audio session's RTP statistics");
/*dismantle the outgoing graph*/
ms_connection_helper_start(&h);
ms_connection_helper_unlink(&h,stream->soundread,-1,0);
if (stream->read_resampler!=NULL)
ms_connection_helper_unlink(&h,stream->read_resampler,0,0);
if (stream->ec!=NULL)
ms_connection_helper_unlink(&h,stream->ec,1,1);
if (stream->volsend!=NULL)
ms_connection_helper_unlink(&h,stream->volsend,0,0);
if (stream->dtmfgen_rtp)
ms_connection_helper_unlink(&h,stream->dtmfgen_rtp,0,0);
ms_connection_helper_unlink(&h,stream->encoder,0,0);
ms_connection_helper_unlink(&h,stream->rtpsend,0,-1);
/*dismantle the receiving graph*/
ms_connection_helper_start(&h);
ms_connection_helper_unlink(&h,stream->rtprecv,-1,0);
ms_connection_helper_unlink(&h,stream->decoder,0,0);
ms_connection_helper_unlink(&h,stream->dtmfgen,0,0);
if (stream->volrecv!=NULL)
ms_connection_helper_unlink(&h,stream->volrecv,0,0);
if (stream->equalizer)
ms_connection_helper_unlink(&h,stream->equalizer,0,0);
if (stream->ec!=NULL)
ms_connection_helper_unlink(&h,stream->ec,0,0);
if (stream->write_resampler!=NULL)
ms_connection_helper_unlink(&h,stream->write_resampler,0,0);
ms_connection_helper_unlink(&h,stream->soundwrite,0,-1);
if (stream->dummy){
stop_preload_graph(stream);
}else if (stream->start_time!=0){
ms_ticker_detach(stream->ticker,stream->soundread);
ms_ticker_detach(stream->ticker,stream->rtprecv);
rtp_stats_display(rtp_session_get_stats(stream->session),"Audio session's RTP statistics");
/*dismantle the outgoing graph*/
ms_connection_helper_start(&h);
ms_connection_helper_unlink(&h,stream->soundread,-1,0);
if (stream->read_resampler!=NULL)
ms_connection_helper_unlink(&h,stream->read_resampler,0,0);
if (stream->ec!=NULL)
ms_connection_helper_unlink(&h,stream->ec,1,1);
if (stream->volsend!=NULL)
ms_connection_helper_unlink(&h,stream->volsend,0,0);
if (stream->dtmfgen_rtp)
ms_connection_helper_unlink(&h,stream->dtmfgen_rtp,0,0);
ms_connection_helper_unlink(&h,stream->encoder,0,0);
ms_connection_helper_unlink(&h,stream->rtpsend,0,-1);
/*dismantle the receiving graph*/
ms_connection_helper_start(&h);
ms_connection_helper_unlink(&h,stream->rtprecv,-1,0);
ms_connection_helper_unlink(&h,stream->decoder,0,0);
ms_connection_helper_unlink(&h,stream->dtmfgen,0,0);
if (stream->volrecv!=NULL)
ms_connection_helper_unlink(&h,stream->volrecv,0,0);
if (stream->equalizer)
ms_connection_helper_unlink(&h,stream->equalizer,0,0);
if (stream->ec!=NULL)
ms_connection_helper_unlink(&h,stream->ec,0,0);
if (stream->write_resampler!=NULL)
ms_connection_helper_unlink(&h,stream->write_resampler,0,0);
ms_connection_helper_unlink(&h,stream->soundwrite,0,-1);
}
}
audio_stream_free(stream);
ms_filter_log_statistics();
......