Commit 29c45b48 authored by jehan's avatar jehan

-improve media_stream api

-factorize audio_iterate, video_iterate, media_iterate
-add up/down bw stat to MediaStream
-fix bitrate controller driver for opus
-add Mediastream tester
parent 4d413735
dnl Process this file with autoconf to produce a configure script.
AC_INIT([mediastreamer],[2.9.1])
AC_INIT([mediastreamer],[2.9.2])
AC_MSG_NOTICE([$PACKAGE_NAME-$PACKAGE_VERSION A mediastreaming library for telephony application.])
AC_MSG_NOTICE([licensed under the terms of the General Public License (GPL)])
......
......@@ -75,6 +75,14 @@ typedef enum StreamType {
VideoStreamType
} StreamType;
typedef struct _MediaStream MediaStream;
/*
* internal cb to process rtcp stream
* */
typedef void (*media_stream_process_rtcp)(MediaStream *stream, mblk_t *m);
struct _MediaStream {
StreamType type;
MSTicker *ticker;
......@@ -95,9 +103,21 @@ struct _MediaStream {
bool_t use_rc;
bool_t is_beginning;
bool_t pad[2];
/**
* defines encoder target network bit rate, uses #media_stream_set_network_bitrate() setter.
* */
int target_bitrate;
media_stream_process_rtcp process_rtcp;
float up_bw; /*computed upload bw*/
float down_bw; /*computed upload bw*/
time_t last_bw_sampling_time;
};
typedef struct _MediaStream MediaStream;
/**
* @addtogroup audio_stream_api
* @{
**/
MS2_PUBLIC void media_stream_set_rtcp_information(MediaStream *stream, const char *cname, const char *tool);
......@@ -112,17 +132,47 @@ MS2_PUBLIC void media_stream_enable_adaptive_jittcomp(MediaStream *stream, bool_
MS2_PUBLIC bool_t media_stream_enable_srtp(MediaStream* stream, enum ortp_srtp_crypto_suite_t suite, const char* snd_key, const char* rcv_key);
MS2_PUBLIC const MSQualityIndicator *media_stream_get_quality_indicator(MediaStream *stream);
/* *
* returns a realtime indicator of the stream quality between 0 and 5
* */
MS2_PUBLIC float media_stream_get_quality_rating(MediaStream *stream);
MS2_PUBLIC float media_stream_get_average_quality_rating(MediaStream *stream);
/*shall only called internally*/
void media_stream_iterate(MediaStream * stream);
/**
* @addtogroup audio_stream_api
* @{
**/
* <br>For multirate codecs like OPUS, encoder output target bitrate must be set.
* <br>Encoder will compute output codec bitrate from this value.
* <br> default value is the value corresponding the rtp PayloadType
* @param stream stream to apply parameter on
* @param target_bitrate in bit per seconds
* @return 0 if succeed
* */
MS2_PUBLIC int media_stream_set_target_network_bitrate(MediaStream *stream,int target_bitrate);
/**
* get the stream target bitrate.
* @param stream stream to apply parameter on
* @param target_bitrate in bit per seconds
* */
MS2_PUBLIC int media_stream_get_target_network_bitrate(const MediaStream *stream);
/**
* get current stream upload bitrate. Value is updated every seconds
* @param stream
* @return bitrate in bit per seconds
* */
MS2_PUBLIC float media_stream_get_up_bw(const MediaStream *stream);
/**
* get current stream download bitrate. Value is updated every seconds
* @param stream
* @return bitrate in bit per seconds
* */
MS2_PUBLIC float media_stream_get_down_bw(const MediaStream *stream);
void media_stream_iterate(MediaStream * stream);
typedef enum EchoLimiterType{
ELInactive,
......@@ -279,45 +329,67 @@ MS2_PUBLIC bool_t audio_stream_alive(AudioStream * stream, int timeout);
*/
MS2_PUBLIC void audio_stream_iterate(AudioStream *stream);
/*enable echo-limiter dispositve: one MSVolume in input branch controls a MSVolume in the output branch*/
/**
* enable echo-limiter dispositve: one MSVolume in input branch controls a MSVolume in the output branch
* */
MS2_PUBLIC void audio_stream_enable_echo_limiter(AudioStream *stream, EchoLimiterType type);
/*enable gain control, to be done before start() */
/**
* enable gain control, to be done before start()
* */
MS2_PUBLIC void audio_stream_enable_gain_control(AudioStream *stream, bool_t val);
/*enable automatic gain control, to be done before start() */
/**
* enable automatic gain control, to be done before start()
* */
MS2_PUBLIC void audio_stream_enable_automatic_gain_control(AudioStream *stream, bool_t val);
/*to be done before start */
/**
* to be done before start
* */
MS2_PUBLIC void audio_stream_set_echo_canceller_params(AudioStream *st, int tail_len_ms, int delay_ms, int framesize);
/*enable adaptive rate control */
/**
* enable adaptive rate control
* */
static inline void audio_stream_enable_adaptive_bitrate_control(AudioStream *stream, bool_t enabled) {
media_stream_enable_adaptive_bitrate_control(&stream->ms, enabled);
}
/* Enable adaptive jitter compensation */
/**
* Enable adaptive jitter compensation
* */
static inline void audio_stream_enable_adaptive_jittcomp(AudioStream *stream, bool_t enabled) {
media_stream_enable_adaptive_jittcomp(&stream->ms, enabled);
}
MS2_PUBLIC void audio_stream_set_mic_gain(AudioStream *stream, float gain);
/* enable/disable rtp stream */
/**
* enable/disable rtp stream
* */
MS2_PUBLIC void audio_stream_mute_rtp(AudioStream *stream, bool_t val);
/*enable noise gate, must be done before start()*/
/**
* enable noise gate, must be done before start()
* */
MS2_PUBLIC void audio_stream_enable_noise_gate(AudioStream *stream, bool_t val);
/*enable parametric equalizer in the stream that goes to the speaker*/
/**
* enable parametric equalizer in the stream that goes to the speaker
* */
MS2_PUBLIC void audio_stream_enable_equalizer(AudioStream *stream, bool_t enabled);
MS2_PUBLIC void audio_stream_equalizer_set_gain(AudioStream *stream, int frequency, float gain, int freq_width);
/* stop the audio streaming thread and free everything*/
/**
* stop the audio streaming thread and free everything
* */
MS2_PUBLIC void audio_stream_stop (AudioStream * stream);
/* send a dtmf */
/**
* send a dtmf
* */
MS2_PUBLIC int audio_stream_send_dtmf (AudioStream * stream, char dtmf);
MS2_PUBLIC int audio_stream_mixed_record_open(AudioStream *st, const char*filename);
......
......@@ -104,7 +104,9 @@ static void audio_stream_configure_resampler(MSFilter *resampler,MSFilter *from,
from->desc->name, to->desc->name, from_rate, to_rate, from_channels, to_channels);
}
static void audio_stream_process_rtcp(AudioStream *stream, mblk_t *m){
static void audio_stream_process_rtcp(MediaStream *media_stream, mblk_t *m){
AudioStream *stream=(AudioStream*)media_stream;
stream->last_packet_time=ms_time(NULL);
do{
const report_block_t *rb=NULL;
if (rtcp_is_SR(m)){
......@@ -118,8 +120,8 @@ static void audio_stream_process_rtcp(AudioStream *stream, mblk_t *m){
float flost;
ij=report_block_get_interarrival_jitter(rb);
flost=(float)(100.0*report_block_get_fraction_lost(rb)/256.0);
ms_message("audio_stream_iterate(): remote statistics available\n\tremote's interarrival jitter=%u\n"
"\tremote's lost packets percentage since last report=%f\n\tround trip time=%f seconds",ij,flost,rt);
ms_message("audio_stream_iterate[%p]: remote statistics available\n\tremote's interarrival jitter=%u\n"
"\tremote's lost packets percentage since last report=%f\n\tround trip time=%f seconds",stream,ij,flost,rt);
if (stream->ms.rc) ms_bitrate_controller_process_rtcp(stream->ms.rc,m);
if (stream->ms.qi) ms_quality_indicator_update_from_feedback(stream->ms.qi,m);
}
......@@ -127,21 +129,6 @@ static void audio_stream_process_rtcp(AudioStream *stream, mblk_t *m){
}
void audio_stream_iterate(AudioStream *stream){
if (stream->ms.evq){
OrtpEvent *ev=ortp_ev_queue_get(stream->ms.evq);
if (ev!=NULL){
OrtpEventType evt=ortp_event_get_type(ev);
if (evt==ORTP_EVENT_RTCP_PACKET_RECEIVED){
audio_stream_process_rtcp(stream,ortp_event_get_data(ev)->packet);
stream->last_packet_time=ms_time(NULL);
}else if (evt==ORTP_EVENT_RTCP_PACKET_EMITTED){
ms_message("audio_stream_iterate(): local statistics available\n\tLocal's current jitter buffer size:%f ms",rtp_session_get_jitter_stats(stream->ms.session)->jitter_buffer_size_ms);
}else if ((evt==ORTP_EVENT_STUN_PACKET_RECEIVED)&&(stream->ms.ice_check_list)){
ice_handle_stun_packet(stream->ms.ice_check_list,stream->ms.session,ortp_event_get_data(ev));
}
ortp_event_destroy(ev);
}
}
media_stream_iterate(&stream->ms);
}
......@@ -386,10 +373,12 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char
/* give the encoder/decoder some parameters*/
ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
ms_message("Payload's bitrate is %i",pt->normal_bitrate);
if (pt->normal_bitrate>0){
ms_message("Setting audio encoder network bitrate to %i",pt->normal_bitrate);
ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_BITRATE,&pt->normal_bitrate);
if (stream->ms.target_bitrate<=0) {
ms_message("target bitrate not set for stream [%p] using payload's bitrate is %i",stream,stream->ms.target_bitrate=pt->normal_bitrate);
}
if (stream->ms.target_bitrate>0){
ms_message("Setting audio encoder network bitrate to [%i] on stream [%p]",stream->ms.target_bitrate,stream);
ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_BITRATE,&stream->ms.target_bitrate);
}
ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_NCHANNELS,&pt->channels);
ms_filter_call_method(stream->ms.decoder,MS_FILTER_SET_SAMPLE_RATE,&sample_rate);
......@@ -657,7 +646,7 @@ AudioStream *audio_stream_new(int loc_rtp_port, int loc_rtcp_port, bool_t ipv6){
stream->ms.rtpsend=ms_filter_new(MS_RTP_SEND_ID);
stream->ms.ice_check_list=NULL;
stream->ms.qi=ms_quality_indicator_new(stream->ms.session);
stream->ms.process_rtcp=audio_stream_process_rtcp;
if (ec_desc!=NULL)
stream->ec=ms_filter_new_from_desc(ec_desc);
else
......
......@@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mediastreamer2/bitratecontrol.h"
static const int max_ptime=100;
static const int min_ptime=10;
int ms_bitrate_driver_execute_action(MSBitrateDriver *obj, const MSRateControlAction *action){
if (obj->desc->execute_action)
......@@ -56,22 +57,46 @@ struct _MSAudioBitrateDriver{
typedef struct _MSAudioBitrateDriver MSAudioBitrateDriver;
static void apply_ptime(MSAudioBitrateDriver *obj){
static int apply_ptime(MSAudioBitrateDriver *obj,int target_ptime){
char tmp[64];
snprintf(tmp,sizeof(tmp),"ptime=%i",obj->cur_ptime);
if (ms_filter_call_method(obj->encoder,MS_FILTER_ADD_FMTP,tmp)!=0){
ms_message("AudioBitrateController: failed ptime command.");
}else ms_message("AudioBitrateController: ptime changed to %i",obj->cur_ptime);
int result=-1;;
if (min_ptime <min_ptime || target_ptime>max_ptime) {
ms_error("cannot apply ptime value [%i] on [%p] because out of range [%i..%i]",target_ptime,obj,min_ptime,max_ptime);
return -1;
}
if (ms_filter_has_method(obj->encoder,MS_AUDIO_ENCODER_SET_PTIME)) {
result = ms_filter_call_method(obj->encoder,MS_AUDIO_ENCODER_SET_PTIME,&target_ptime);
} else {
/*legacy*/
snprintf(tmp,sizeof(tmp),"ptime=%i",target_ptime);
result = ms_filter_call_method(obj->encoder,MS_FILTER_ADD_FMTP,tmp);
}
if (ms_filter_has_method(obj->encoder,MS_AUDIO_ENCODER_GET_PTIME)) {
ms_filter_call_method(obj->encoder,MS_AUDIO_ENCODER_GET_PTIME,&obj->cur_ptime);
} else {
/*legacy*/
if (result==0) {
obj->cur_ptime=target_ptime;
} /*else ptime remain unchanged*/
}
if (result == 0) {
ms_message("AudioBitrateController [%p]: ptime is now [%i ms]",obj,obj->cur_ptime);
} else {
ms_message("AudioBitrateController [%p]: cannot move ptime from [%i ms] to [%i ms]",obj,obj->cur_ptime,target_ptime);
}
return result;
}
static int inc_ptime(MSAudioBitrateDriver *obj){
if (obj->cur_ptime>=max_ptime){
ms_message("MSAudioBitrateDriver: maximum ptime reached");
return -1;
}
obj->cur_ptime+=obj->min_ptime;
apply_ptime(obj);
return 0;
return apply_ptime(obj,obj->cur_ptime+obj->min_ptime);
}
static int dec_ptime(MSAudioBitrateDriver *obj){
return apply_ptime(obj,obj->cur_ptime-obj->min_ptime);
}
static int audio_bitrate_driver_execute_action(MSBitrateDriver *objbase, const MSRateControlAction *action){
......@@ -86,7 +111,7 @@ static int audio_bitrate_driver_execute_action(MSBitrateDriver *objbase, const M
}else
obj->cur_bitrate=obj->nom_bitrate;
}
if (obj->cur_ptime==0){
if (obj->cur_ptime==0 || ms_filter_has_method(obj->encoder,MS_AUDIO_ENCODER_GET_PTIME)){ /*always sync current ptime if possible*/
ms_filter_call_method(obj->encoder,MS_AUDIO_ENCODER_GET_PTIME,&obj->cur_ptime);
if (obj->cur_ptime==0){
ms_warning("MSAudioBitrateDriver: encoder %s does not implement MS_AUDIO_ENCODER_GET_PTIME. Consider to implement this method for better accuracy of rate control.",obj->encoder->desc->name);
......@@ -96,7 +121,7 @@ static int audio_bitrate_driver_execute_action(MSBitrateDriver *objbase, const M
if (action->type==MSRateControlActionDecreaseBitrate){
/*reducing bitrate of the codec isn't sufficient. Increasing ptime is much more efficient*/
if (inc_ptime(obj)==-1){
if (inc_ptime(obj)){
if (obj->nom_bitrate>0){
int cur_br=0;
int new_br;
......@@ -113,8 +138,7 @@ static int audio_bitrate_driver_execute_action(MSBitrateDriver *objbase, const M
ms_message("MSAudioBitrateDriver: Attempting to reduce audio bitrate to %i",new_br);
if (ms_filter_call_method(obj->encoder,MS_FILTER_SET_BITRATE,&new_br)!=0){
ms_message("MSAudioBitrateDriver: SET_BITRATE failed, incrementing ptime");
inc_ptime(obj);
return 0;
return inc_ptime(obj);
}
new_br=0;
ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&new_br);
......@@ -123,7 +147,7 @@ static int audio_bitrate_driver_execute_action(MSBitrateDriver *objbase, const M
}
}
}else if (action->type==MSRateControlActionDecreasePacketRate){
inc_ptime(obj);
return inc_ptime(obj);
}else if (action->type==MSRateControlActionIncreaseQuality){
if (obj->nom_bitrate>0){
if (ms_filter_call_method(obj->encoder,MS_FILTER_GET_BITRATE,&obj->cur_bitrate)==0){
......@@ -140,8 +164,7 @@ static int audio_bitrate_driver_execute_action(MSBitrateDriver *objbase, const M
}
if (obj->cur_ptime>obj->min_ptime){
obj->cur_ptime-=obj->min_ptime;
apply_ptime(obj);
return dec_ptime(obj);
}else return -1;
}
return 0;
......
......@@ -34,6 +34,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#if defined(_WIN32_WCE)
time_t
ms_time(time_t *t) {
......@@ -272,10 +273,34 @@ void media_stream_iterate(MediaStream *stream){
rtp_session_set_rtcp_report_interval(stream->session,5000);
stream->is_beginning=FALSE;
}
if ((curtime-stream->last_bw_sampling_time)>=1) {
/*update bandwidth stat every second more or less*/
stream->up_bw=rtp_session_compute_send_bandwidth(stream->session);
stream->down_bw=rtp_session_compute_recv_bandwidth(stream->session);
stream->last_bw_sampling_time=curtime;
}
if (stream->ice_check_list) ice_check_list_process(stream->ice_check_list,stream->session);
/*we choose to update the quality indicator as much as possible, since local statistics can be computed realtime. */
if (stream->qi && curtime>stream->last_iterate_time) ms_quality_indicator_update_local(stream->qi);
stream->last_iterate_time=curtime;
if (stream->evq){
OrtpEvent *ev=ortp_ev_queue_get(stream->evq);
if (ev!=NULL){
OrtpEventType evt=ortp_event_get_type(ev);
if (evt==ORTP_EVENT_RTCP_PACKET_RECEIVED){
stream->process_rtcp(stream,ortp_event_get_data(ev)->packet);
}else if (evt==ORTP_EVENT_RTCP_PACKET_EMITTED){
ms_message("%s_stream_iterate[%p]: local statistics available\n\tLocal's current jitter buffer size:%f ms" , media_stream_type_str(stream)
, stream
, rtp_session_get_jitter_stats(stream->session)->jitter_buffer_size_ms);
}else if ((evt==ORTP_EVENT_STUN_PACKET_RECEIVED)&&(stream->ice_check_list)){
ice_handle_stun_packet(stream->ice_check_list,stream->session,ortp_event_get_data(ev));
}
ortp_event_destroy(ev);
}
}
}
float media_stream_get_quality_rating(MediaStream *stream){
......@@ -292,4 +317,19 @@ float media_stream_get_average_quality_rating(MediaStream *stream){
return -1;
}
int media_stream_set_target_network_bitrate(MediaStream *stream,int target_bitrate) {
stream->target_bitrate=target_bitrate;
return 0;
}
int media_stream_get_target_network_bitrate(const MediaStream *stream) {
return stream->target_bitrate;
}
MS2_PUBLIC float media_stream_get_up_bw(const MediaStream *stream) {
return stream->up_bw;
}
MS2_PUBLIC float media_stream_get_down_bw(const MediaStream *stream) {
return stream->down_bw;
}
......@@ -74,7 +74,8 @@ static void event_cb(void *ud, MSFilter* f, unsigned int event, void *eventdata)
}
}
static void video_steam_process_rtcp(VideoStream *stream, mblk_t *m){
static void video_steam_process_rtcp(MediaStream *media_stream, mblk_t *m){
VideoStream *stream = (VideoStream *)media_stream;
do{
if (rtcp_is_SR(m)){
const report_block_t *rb;
......@@ -86,7 +87,7 @@ static void video_steam_process_rtcp(VideoStream *stream, mblk_t *m){
float flost;
ij=report_block_get_interarrival_jitter(rb);
flost=(float)(100.0*report_block_get_fraction_lost(rb)/256.0);
ms_message("video_steam_process_rtcp: interarrival jitter=%u , lost packets percentage since last report=%f, round trip time=%f seconds",ij,flost,rt);
ms_message("video_steam_process_rtcp[%p]: interarrival jitter=%u , lost packets percentage since last report=%f, round trip time=%f seconds",stream,ij,flost,rt);
if (stream->ms.rc)
ms_bitrate_controller_process_rtcp(stream->ms.rc,m);
}
......@@ -104,24 +105,6 @@ static void stop_preload_graph(VideoStream *stream){
}
void video_stream_iterate(VideoStream *stream){
/*
if (stream->output!=NULL)
ms_filter_call_method_noarg(stream->output,
MS_VIDEO_OUT_HANDLE_RESIZING);
*/
if (stream->ms.evq){
OrtpEvent *ev;
while (NULL != (ev=ortp_ev_queue_get(stream->ms.evq))) {
OrtpEventType evt=ortp_event_get_type(ev);
if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED){
OrtpEventData *evd=ortp_event_get_data(ev);
video_steam_process_rtcp(stream,evd->packet);
}else if ((evt == ORTP_EVENT_STUN_PACKET_RECEIVED) && (stream->ms.ice_check_list)) {
ice_handle_stun_packet(stream->ms.ice_check_list,stream->ms.session,ortp_event_get_data(ev));
}
ortp_event_destroy(ev);
}
}
media_stream_iterate(&stream->ms);
}
......@@ -158,7 +141,7 @@ VideoStream *video_stream_new(int loc_rtp_port, int loc_rtcp_port, bool_t use_ip
stream->source_performs_encoding = FALSE;
stream->output_performs_decoding = FALSE;
choose_display_name(stream);
stream->ms.process_rtcp=video_steam_process_rtcp;
return stream;
}
......
......@@ -10,7 +10,7 @@ noinst_PROGRAMS=mediastreamer2_tester
mediastreamer2_tester_SOURCES= \
mediastreamer2_tester.c mediastreamer2_tester.h mediastreamer2_tester_private.c mediastreamer2_tester_private.h \
mediastreamer2_basic_audio_tester.c mediastreamer2_sound_card_tester.c
mediastreamer2_basic_audio_tester.c mediastreamer2_sound_card_tester.c mediastreamer2_audio_stream_tester.c
mediastreamer2_tester_CFLAGS=$(CUNIT_CFLAGS) $(STRICT_OPTIONS) $(ORTP_CFLAGS)
......
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006-2013 Belledonne Communications, Grenoble
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/dtmfgen.h"
#include "mediastreamer2/msfileplayer.h"
#include "mediastreamer2/msfilerec.h"
#include "mediastreamer2/msrtp.h"
#include "mediastreamer2/mstonedetector.h"
#include "private.h"
#include "mediastreamer2_tester.h"
#include "mediastreamer2_tester_private.h"
#include <stdio.h>
#include "CUnit/Basic.h"
#ifdef _MSC_VER
#define unlink _unlink
#endif
static RtpProfile rtp_profile;
#define OPUS_PAYLOAD_TYPE 121
#define SPEEX16_PAYLOAD_TYPE 122
#define SILK16_PAYLOAD_TYPE 123
static int tester_init(void) {
ms_init();
ms_filter_enable_statistics(TRUE);
ortp_init();
rtp_profile_set_payload (&rtp_profile,0,&payload_type_pcmu8000);
rtp_profile_set_payload (&rtp_profile,OPUS_PAYLOAD_TYPE,&payload_type_opus);
rtp_profile_set_payload (&rtp_profile,SPEEX16_PAYLOAD_TYPE,&payload_type_speex_wb);
rtp_profile_set_payload (&rtp_profile,SILK16_PAYLOAD_TYPE,&payload_type_silk_wb);
return 0;
}
static int tester_cleanup(void) {
ms_exit();
rtp_profile_clear_all(&rtp_profile);
return 0;
}
#define MARIELLE_RTP_PORT 2564
#define MARIELLE_RTCP_PORT 2565
#define MARIELLE_IP "127.0.0.1"
#define MARGAUX_RTP_PORT 9864
#define MARGAUX_RTCP_PORT 9865
#define MARGAUX_IP "127.0.0.1"
#define HELLO_8K_1S_FILE "./sounds/hello8000-1s.wav"
#define HELLO_16K_1S_FILE "./sounds/hello16000-1s.wav"
#define RECORDED_8K_1S_FILE "recorded_helleo8000-1s.wav"
typedef struct _stats_t {
rtp_stats_t rtp;
int number_of_EndOfFile;
} stats_t;
static void reset_stats(stats_t* s) {
memset(s,0,sizeof(stats_t));
}
bool_t wait_for_list(MSList* mss,int* counter,int value,int timeout_ms) {
int retry=0;
MSList* iterator;
while (*counter<value && retry++ <timeout_ms/100) {
for (iterator=mss;iterator!=NULL;iterator=iterator->next) {
MediaStream* stream = (MediaStream*)(iterator->data);
media_stream_iterate(stream);
if (retry%10==0) {
ms_message("stream [%p] bandwidth usage: [d=%.1f,u=%.1f] kbit/sec" , stream
, media_stream_get_down_bw(stream)/1000
, media_stream_get_up_bw(stream)/1000);
}
}
ms_usleep(100000);
}
if(*counter<value) return FALSE;
else return TRUE;
}
bool_t wait_for_until(MediaStream* ms_1, MediaStream* ms_2,int* counter,int value,int timeout) {
MSList* mss=NULL;
bool_t result;
if (ms_1)
mss=ms_list_append(mss,ms_1);
if (ms_2)
mss=ms_list_append(mss,ms_2);
result=wait_for_list(mss,counter,value,timeout);
ms_list_free(mss);
return result;
}
bool_t wait_for(MediaStream* ms_1, MediaStream* ms_2,int* counter,int value) {
return wait_for_until( ms_1, ms_2,counter,value,2000);
}
static void notify_cb(void *user_data, MSFilter *f, unsigned int event, void *eventdata) {
stats_t* stats = (stats_t*)user_data;
switch (event) {
case MS_FILE_PLAYER_EOF: {
ms_message("EndOfFile received");
stats->number_of_EndOfFile++;
break;
}
break;
}
}
typedef struct _stream_manager_t {
AudioStream* stream;
int local_rtp;
int local_rtcp;
stats_t stats;
} stream_manager_t ;
static stream_manager_t * stream_manager_new() {
stream_manager_t * mgr = ms_new0(stream_manager_t,1);
mgr->local_rtp= (rand() % ((2^16)-1024) + 1024) & ~0x1;
mgr->local_rtcp=mgr->local_rtp+1;
mgr->stream = audio_stream_new (mgr->local_rtp, mgr->local_rtcp,FALSE);
return mgr;
}
static void stream_manager_delete(stream_manager_t * mgr) {
audio_stream_stop(mgr->stream);
ms_free(mgr);
}
static void stream_manager_start( stream_manager_t * mgr
,int payload_type
,int remote_port
,int target_bitrate
,const char* player_file
,const char* recorder_file) {
media_stream_set_target_network_bitrate(&mgr->stream->ms,target_bitrate);
CU_ASSERT_EQUAL(audio_stream_start_full(mgr->stream
, &rtp_profile
, "127.0.0.1"
, remote_port
, "127.0.0.1"
, remote_port+1
, payload_type
, 50
, player_file
, recorder_file
, NULL
, NULL
, 0),0);
}
static void basic_audio_stream() {
AudioStream * marielle = audio_stream_new (MARIELLE_RTP_PORT, MARIELLE_RTCP_PORT,FALSE);
stats_t marielle_stats;
AudioStream * margaux = audio_stream_new (MARGAUX_RTP_PORT,MARGAUX_RTCP_PORT, FALSE);
stats_t margaux_stats;
RtpProfile* profile = rtp_profile_new("default profile");
reset_stats(&marielle_stats);
reset_stats(&margaux_stats);
rtp_profile_set_payload (profile,0,&payload_type_pcmu8000);
CU_ASSERT_EQUAL(audio_stream_start_full(marielle
, profile
, MARGAUX_IP
, MARGAUX_RTP_PORT
, MARGAUX_IP
, MARGAUX_RTCP_PORT
, 0
, 50
, HELLO_8K_1S_FILE
, NULL
, NULL
, NULL
, 0),0);
ms_filter_set_notify_callback(marielle->soundread, notify_cb, &marielle_stats);
CU_ASSERT_EQUAL(audio_stream_start_full(margaux
, profile
, MARIELLE_IP
, MARIELLE_RTP_PORT
, MARIELLE_IP
, MARIELLE_RTCP_PORT
, 0
, 50
, NULL
, RECORDED_8K_1S_FILE
, NULL
, NULL
, 0),0);
CU_ASSERT_TRUE(wait_for_until(&marielle->ms,&margaux->ms,&marielle_stats.number_of_EndOfFile,1,12000));
/*last chance to purge jitter buffer*/
audio_stream_iterate(margaux);
audio_stream_get_local_rtp_stats(marielle,&marielle_stats.rtp);
audio_stream_get_local_rtp_stats(margaux,&margaux_stats.rtp);
/*no packet lose is assume*/
CU_ASSERT_EQUAL(marielle_stats.rtp.sent,margaux_stats.rtp.recv);
audio_stream_stop(marielle);
audio_stream_stop(margaux);
unlink(RECORDED_8K_1S_FILE);
}
#define EDGE_BW 10000
static void adaptive_audio_stream(int codec_payload, int initial_bitrate,int target_bw, int max_recv_rtcp_packet) {
stream_manager_t * marielle = stream_manager_new();
stream_manager_t * margaux = stream_manager_new();
int pause_time=0;