From 3d99d13bf68e0864d540f3c91dfa7af3964a1920 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 25 May 2010 18:04:02 +0200 Subject: [PATCH 1/6] sound daemon: work in progress --- coreapi/linphonecore_utils.h | 50 +++++++++ coreapi/lsd.c | 198 +++++++++++++++++++++++++++++++++++ 2 files changed, 248 insertions(+) create mode 100644 coreapi/linphonecore_utils.h create mode 100644 coreapi/lsd.c diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h new file mode 100644 index 000000000..1eeda5f3f --- /dev/null +++ b/coreapi/linphonecore_utils.h @@ -0,0 +1,50 @@ +/* +linphone +Copyright (C) 2010 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef LINPHONECORE_UTILS_H +#define LINPHONECORE_UTILS_H + +#ifdef IN_LINPHONE +#include "linphonecore.h" +#else +#include "linphone/linphonecore.h" +#endif + +typedef struct _LsdPlayer LsdPlayer; +typedef struct _LinphoneSoundDaemon LinphoneSoundDaemon; + +typedef void (*LsdEndOfPlayCallback)(LsdPlayer *p); + +LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname); + +LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd); +void linphone_sound_daemon_release_player(LinphoneSoundDaemon *lsd, LsdPlayer *lsdplayer); + +MSFilter *linphone_sound_daemon_get_proxy(LinphoneSoundDaemon *obj); + +void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj); + +void lsd_player_set_callback(LsdPlayer *p, LsdEndOfPlayCallback cb); +void lsd_player_set_user_pointer(LsdPlayer *p, void *up); +void *lsd_player_get_user_pointer(LsdPlayer *p); +int lsd_player_play(LsdPlayer *p, const char *filename); +int lsd_player_stop(LsdPlayer *p); +void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode); + +#endif diff --git a/coreapi/lsd.c b/coreapi/lsd.c new file mode 100644 index 000000000..d4f6dae48 --- /dev/null +++ b/coreapi/lsd.c @@ -0,0 +1,198 @@ +/* +linphone +Copyright (C) 2010 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* Linphone Sound Daemon: is a lightweight utility to play sounds to speaker during a conversation. + This is useful for embedded platforms, where sound apis are not performant enough to allow + simultaneous sound access. +*/ + +#include "linphonecore_utils.h" +#include "mediastreamer2/mssndcard.h" +#include "mediastreamer2/msvolume.h" + + +#define MAX_BRANCHES 10 + + +struct _LsdPlayer{ + struct _LinphoneSoundDaemon *lsd; + MSFilter *player; + MSFilter *rateconv; + MSFilter *chanadapter; + MSFilter *volumectl; + LsdEndOfPlayCallback eop_cb; + void *user_data; + bool_t loopmode; +}; + +struct _LinphoneSoundDaemon { + int out_rate; + int out_nchans; + MSFilter *mixer; + MSFilter *soundout; + LsdPlayer branches[MAX_BRANCHES]; +}; + + +LsdPlayer *linphone_sound_daemon_get_player(LinphoneSoundDaemon *obj){ + int i; + for(i=0;ibranches[i]; + MSFilter *p=b->player; + int state; + ms_filter_call_method(p,MS_PLAYER_GET_STATE,&state); + if (state==MSPlayerClosed){ + return b; + } + } + ms_warning("No more free players !"); + return NULL; +} + +void linphone_sound_daemon_release_player(LinphoneSoundDaemon *obj, LsdPlayer * player){ + int state; + float gain=1; + ms_filter_call_method(player->player,MS_PLAYER_GET_STATE,&state); + if (state!=MSPlayerClosed){ + ms_filter_call_method(player->player,MS_PLAYER_CLOSE,&state); + } + ms_filter_call_method(player->volumectl,MS_VOLUME_SET_GAIN,&gain); +} + +int lsd_player_stop(LsdPlayer *p){ + ms_filter_call_method_noarg(p->player,MS_PLAYER_PAUSE); + return 0; +} + +MSFilter *linphone_sound_daemon_get_proxy(LinphoneSoundDaemon *obj); +void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj); + +static void lsd_player_init(LsdPlayer *p, MSConnectionPoint mixer, MSFilterId playerid, LinphoneSoundDaemon *lsd){ + MSConnectionHelper h; + p->player=ms_filter_new(playerid); + p->rateconv=ms_filter_new(MS_RESAMPLE_ID); + p->chanadapter=NULL; + p->volumectl=ms_filter_new(MS_VOLUME_ID); + + ms_connection_helper_start(&h); + ms_connection_helper_link(&h,p->player,-1,0); + ms_connection_helper_link(&h,p->rateconv,0,0); + ms_connection_helper_link(&h,p->chanadapter,0,0); + ms_connection_helper_link(&h,p->volumectl,0,0); + ms_connection_helper_link(&h,mixer.filter,mixer.pin,-1); + p->lsd=lsd; +} + +static void lsd_player_uninit(LsdPlayer *p, MSConnectionPoint mixer){ + MSConnectionHelper h; + + ms_connection_helper_start(&h); + ms_connection_helper_unlink (&h,p->player,-1,0); + ms_connection_helper_unlink(&h,p->rateconv,0,0); + ms_connection_helper_unlink(&h,p->chanadapter,0,0); + ms_connection_helper_unlink(&h,p->volumectl,0,0); + ms_connection_helper_unlink(&h,mixer.filter,mixer.pin,-1); + + ms_filter_destroy(p->player); + ms_filter_destroy(p->rateconv); + ms_filter_destroy(p->chanadapter); + ms_filter_destroy(p->volumectl); +} + +void lsd_player_set_callback(LsdPlayer *p, LsdEndOfPlayCallback cb){ + p->eop_cb=cb; +} + +void lsd_player_set_user_pointer(LsdPlayer *p, void *up){ + p->user_data=up; +} + +void *lsd_player_get_user_pointer(LsdPlayer *p){ + return p->user_data; +} + +static void lsd_player_on_eop(void * userdata, unsigned int id, void *arg){ +} + +int lsd_player_play(LsdPlayer *b, const char *filename ){ + int rate,chans; + int state; + LinphoneSoundDaemon *lsd=b->lsd; + + ms_filter_call_method(b->player,MS_PLAYER_GET_STATE,&state); + if (state!=MSPlayerClosed){ + ms_filter_call_method_noarg(b->player,MS_PLAYER_CLOSE); + } + + if (ms_filter_call_method(b->player,MS_PLAYER_OPEN,(void*)filename)!=0){ + return -1; + } + ms_filter_call_method(b->player,MS_FILTER_GET_SAMPLE_RATE,&rate); + ms_filter_call_method(b->player,MS_FILTER_GET_NCHANNELS,&chans); + ms_filter_set_notify_callback (b->player,lsd_player_on_eop,b); + + ms_filter_call_method(b->rateconv,MS_FILTER_SET_SAMPLE_RATE,&rate); + ms_filter_call_method(b->rateconv,MS_FILTER_SET_NCHANNELS,&chans); + ms_filter_call_method(b->rateconv,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&lsd->out_rate); + + ms_filter_call_method(b->chanadapter,MS_FILTER_SET_NCHANNELS,&chans); + ms_filter_call_method(b->chanadapter,MS_FILTER_SET_OUTPUT_NCHANNELS,&lsd->out_nchans); + return 0; +} + +int lsd_player_stop(LsdPlayer *p); +void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode); + +LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ + int i; + MSConnectionPoint mp; + LinphoneSoundDaemon *lsd; + MSSndCard *card=ms_snd_card_manager_get_card( + ms_snd_card_manager_get(), + cardname); + if (card==NULL){ + card=ms_snd_card_manager_get_default_playback_card ( + ms_snd_card_manager_get()); + if (card==NULL){ + ms_error("linphone_sound_daemon_new(): No playback soundcard available"); + return NULL; + } + } + + lsd=ms_new0(LinphoneSoundDaemon,1); + lsd->soundout=ms_snd_card_create_writer(card); + lsd->out_rate=44100; + lsd->out_nchans=2; + ms_filter_call_method(lsd->soundout,MS_FILTER_SET_SAMPLE_RATE,&lsd->out_rate); + ms_filter_call_method(lsd->soundout,MS_FILTER_SET_NCHANNELS,&lsd->out_nchans); + + mp.filter=lsd->filter; + mp.pin=0; + + lsd_player_init(&lsd->branches[0],mp,MS_ITC_SINK_ID,lsd); + for(i=1;ibranches[i],mp,MS_FILE_PLAYER_ID); + } + + return lsd; +} + + +#endif From 0c1555149a5f7d4a8eab7478453473ec115d5798 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 26 May 2010 23:33:02 +0200 Subject: [PATCH 2/6] work in progress --- coreapi/Makefile.am | 3 ++- coreapi/linphonecore_utils.h | 1 + coreapi/lsd.c | 44 +++++++++++++++++++++--------------- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 014ae308e..66a2bf5f6 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -34,7 +34,8 @@ liblinphone_la_SOURCES=\ chat.c \ general_state.c \ sipsetup.c sipsetup.h \ - siplogin.c + siplogin.c \ + lsd.c linphonecore_utils.h liblinphone_la_LDFLAGS= -version-info $(LIBLINPHONE_SO_VERSION) -no-undefined diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index 1eeda5f3f..949cadaa6 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -46,5 +46,6 @@ void *lsd_player_get_user_pointer(LsdPlayer *p); int lsd_player_play(LsdPlayer *p, const char *filename); int lsd_player_stop(LsdPlayer *p); void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode); +void lsd_player_set_gain(LsdPlayer *p, float gain); #endif diff --git a/coreapi/lsd.c b/coreapi/lsd.c index d4f6dae48..34134d00d 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -24,7 +24,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "linphonecore_utils.h" #include "mediastreamer2/mssndcard.h" -#include "mediastreamer2/msvolume.h" +#include "mediastreamer2/msaudiomixer.h" +#include "mediastreamer2/mschanadapter.h" +#include "mediastreamer2/msfileplayer.h" + #define MAX_BRANCHES 10 @@ -35,10 +38,9 @@ struct _LsdPlayer{ MSFilter *player; MSFilter *rateconv; MSFilter *chanadapter; - MSFilter *volumectl; LsdEndOfPlayCallback eop_cb; + int mixer_pin; void *user_data; - bool_t loopmode; }; struct _LinphoneSoundDaemon { @@ -49,7 +51,6 @@ struct _LinphoneSoundDaemon { LsdPlayer branches[MAX_BRANCHES]; }; - LsdPlayer *linphone_sound_daemon_get_player(LinphoneSoundDaemon *obj){ int i; for(i=0;iplayer,MS_PLAYER_GET_STATE,&state); if (state!=MSPlayerClosed){ ms_filter_call_method(player->player,MS_PLAYER_CLOSE,&state); } - ms_filter_call_method(player->volumectl,MS_VOLUME_SET_GAIN,&gain); } int lsd_player_stop(LsdPlayer *p){ @@ -87,15 +87,14 @@ static void lsd_player_init(LsdPlayer *p, MSConnectionPoint mixer, MSFilterId pl MSConnectionHelper h; p->player=ms_filter_new(playerid); p->rateconv=ms_filter_new(MS_RESAMPLE_ID); - p->chanadapter=NULL; - p->volumectl=ms_filter_new(MS_VOLUME_ID); - + p->chanadapter=ms_filter_new(MS_CHANNEL_ADAPTER_ID); + ms_connection_helper_start(&h); ms_connection_helper_link(&h,p->player,-1,0); ms_connection_helper_link(&h,p->rateconv,0,0); ms_connection_helper_link(&h,p->chanadapter,0,0); - ms_connection_helper_link(&h,p->volumectl,0,0); ms_connection_helper_link(&h,mixer.filter,mixer.pin,-1); + p->mixer_pin=mixer.pin; p->lsd=lsd; } @@ -106,13 +105,11 @@ static void lsd_player_uninit(LsdPlayer *p, MSConnectionPoint mixer){ ms_connection_helper_unlink (&h,p->player,-1,0); ms_connection_helper_unlink(&h,p->rateconv,0,0); ms_connection_helper_unlink(&h,p->chanadapter,0,0); - ms_connection_helper_unlink(&h,p->volumectl,0,0); ms_connection_helper_unlink(&h,mixer.filter,mixer.pin,-1); ms_filter_destroy(p->player); ms_filter_destroy(p->rateconv); ms_filter_destroy(p->chanadapter); - ms_filter_destroy(p->volumectl); } void lsd_player_set_callback(LsdPlayer *p, LsdEndOfPlayCallback cb){ @@ -152,12 +149,25 @@ int lsd_player_play(LsdPlayer *b, const char *filename ){ ms_filter_call_method(b->rateconv,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&lsd->out_rate); ms_filter_call_method(b->chanadapter,MS_FILTER_SET_NCHANNELS,&chans); - ms_filter_call_method(b->chanadapter,MS_FILTER_SET_OUTPUT_NCHANNELS,&lsd->out_nchans); + ms_filter_call_method(b->chanadapter,MS_CHANNEL_ADAPTER_SET_OUTPUT_NCHANNELS,&lsd->out_nchans); return 0; } int lsd_player_stop(LsdPlayer *p); -void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode); + +void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode){ + if (ms_filter_get_id(p->player)==MS_FILE_PLAYER_ID){ + int arg=loopmode ? 0 : -1; + ms_filter_call_method(p->player,MS_FILE_PLAYER_LOOP,&arg); + } +} + +void lsd_player_set_gain(LsdPlayer *p, float gain){ + MSAudioMixerCtl gainctl; + gainctl.pin=p->mixer_pin; + gainctl.gain=gain; + ms_filter_call_method(p->lsd->mixer,MS_AUDIO_MIXER_SET_INPUT_GAIN,&gainctl); +} LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ int i; @@ -182,17 +192,15 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ ms_filter_call_method(lsd->soundout,MS_FILTER_SET_SAMPLE_RATE,&lsd->out_rate); ms_filter_call_method(lsd->soundout,MS_FILTER_SET_NCHANNELS,&lsd->out_nchans); - mp.filter=lsd->filter; + mp.filter=lsd->mixer; mp.pin=0; lsd_player_init(&lsd->branches[0],mp,MS_ITC_SINK_ID,lsd); for(i=1;ibranches[i],mp,MS_FILE_PLAYER_ID); + lsd_player_init(&lsd->branches[i],mp,MS_FILE_PLAYER_ID,lsd); } return lsd; } - -#endif From 96bbeb0a8501c6e2e21d6c544d3df0711f09f216 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 27 May 2010 11:33:47 +0200 Subject: [PATCH 3/6] work in progress, near code complete --- coreapi/linphonecore_utils.h | 2 +- coreapi/lsd.c | 59 ++++++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index 949cadaa6..a7f8cfaea 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -36,7 +36,7 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname); LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd); void linphone_sound_daemon_release_player(LinphoneSoundDaemon *lsd, LsdPlayer *lsdplayer); -MSFilter *linphone_sound_daemon_get_proxy(LinphoneSoundDaemon *obj); +struct _MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *obj); void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj); diff --git a/coreapi/lsd.c b/coreapi/lsd.c index 34134d00d..cb0f0af46 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -23,10 +23,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "linphonecore_utils.h" +#include "mediastreamer2/msticker.h" #include "mediastreamer2/mssndcard.h" #include "mediastreamer2/msaudiomixer.h" #include "mediastreamer2/mschanadapter.h" #include "mediastreamer2/msfileplayer.h" +#include "mediastreamer2/msitc.h" @@ -48,9 +50,31 @@ struct _LinphoneSoundDaemon { int out_nchans; MSFilter *mixer; MSFilter *soundout; + MSFilter *itcsink; + MSTicker *ticker; + MSSndCard *proxycard; LsdPlayer branches[MAX_BRANCHES]; }; +static MSFilter *create_writer(MSSndCard *c){ + LinphoneSoundDaemon *lsd=(LinphoneSoundDaemon*)c->data; + return lsd->itcsink; +} + +static MSSndCardDesc proxycard={ + "Linphone Sound Daemon", + /*detect*/ NULL, + /*init*/ NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + /*create_reader*/ NULL, + create_writer, + /*uninit,*/ +}; + LsdPlayer *linphone_sound_daemon_get_player(LinphoneSoundDaemon *obj){ int i; for(i=0;iplayer=ms_filter_new(playerid); @@ -187,10 +208,14 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ lsd=ms_new0(LinphoneSoundDaemon,1); lsd->soundout=ms_snd_card_create_writer(card); + lsd->mixer=ms_filter_new(MS_AUDIO_MIXER_ID); + lsd->itcsink=ms_filter_new(MS_ITC_SINK_ID); lsd->out_rate=44100; lsd->out_nchans=2; ms_filter_call_method(lsd->soundout,MS_FILTER_SET_SAMPLE_RATE,&lsd->out_rate); ms_filter_call_method(lsd->soundout,MS_FILTER_SET_NCHANNELS,&lsd->out_nchans); + ms_filter_call_method(lsd->mixer,MS_FILTER_SET_SAMPLE_RATE,&lsd->out_rate); + ms_filter_call_method(lsd->mixer,MS_FILTER_SET_NCHANNELS,&lsd->out_nchans); mp.filter=lsd->mixer; mp.pin=0; @@ -200,7 +225,35 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ mp.pin=i; lsd_player_init(&lsd->branches[i],mp,MS_FILE_PLAYER_ID,lsd); } + ms_filter_link(lsd->mixer,0,lsd->soundout,0); + lsd->ticker=ms_ticker_new(); + ms_ticker_attach(lsd->ticker,lsd->soundout); + + lsd->proxycard=ms_snd_card_new(&proxycard); + lsd->proxycard->data=lsd; + + ms_filter_call_method(lsd->itcsink,MS_ITC_SINK_CONNECT,lsd->branches[0].player); return lsd; } +void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj){ + int i; + MSConnectionPoint mp; + ms_ticker_detach(obj->ticker,obj->soundout); + mp.filter=obj->mixer; + for(i=0;ibranches[i],mp); + } + ms_ticker_destroy(obj->ticker); + ms_filter_destroy(obj->soundout); + ms_filter_destroy(obj->mixer); + ms_filter_destroy(obj->itcsink); +} + + + +MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *lsd){ + return lsd->proxycard; +} From 359bb6e0a2a217a03c51ace7e599502b6c00dc85 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 28 May 2010 14:15:27 +0200 Subject: [PATCH 4/6] code complete for linphone sound daemon --- coreapi/callbacks.c | 6 ++++-- coreapi/linphonecore.c | 8 +++++--- coreapi/linphonecore_utils.h | 15 ++++++--------- coreapi/lsd.c | 12 +++++++----- coreapi/private.h | 1 + 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index f15404dbf..a4ce8e341 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -100,8 +100,9 @@ static void call_received(SalOp *h){ /* play the ring */ if (lc->sound_conf.ring_sndcard!=NULL){ + MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard; ms_message("Starting local ring..."); - lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard); + lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,ringcard); } linphone_call_set_state(call,LCStateRinging); sal_call_notify_ringing(h); @@ -122,8 +123,9 @@ static void call_ringing(SalOp *h){ if (md==NULL){ if (lc->ringstream!=NULL) return; /*already ringing !*/ if (lc->sound_conf.play_sndcard!=NULL){ + MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; ms_message("Remote ringing..."); - lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,lc->sound_conf.play_sndcard); + lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard); } }else{ /*accept early media */ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f62449e62..d6df2f81a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -621,7 +621,7 @@ static void sound_config_read(LinphoneCore *lc) lp_config_get_int(lc->config,"sound","agc",0)); gain=lp_config_get_float(lc->config,"sound","soft_play_lev",0); - linphone_core_set_soft_play_level(lc,gain); + linphone_core_set_soft_play_level(lc,gain); } static void sip_config_read(LinphoneCore *lc) @@ -2240,7 +2240,8 @@ void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ if (stream){ call->audio_profile=make_profile(lc,call->resultdesc,stream,&used_pt); if (!lc->use_files){ - MSSndCard *playcard=lc->sound_conf.play_sndcard; + MSSndCard *playcard=lc->sound_conf.lsd_card ? + lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; MSSndCard *captcard=lc->sound_conf.capt_sndcard; if (playcard==NULL) { ms_warning("No card defined for playback !"); @@ -2820,7 +2821,8 @@ int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCb lc_callback_obj_init(&lc->preview_finished_cb,func,userdata); lc->preview_finished=0; if (lc->sound_conf.ring_sndcard!=NULL){ - lc->ringstream=ring_start_with_cb(ring,2000,lc->sound_conf.ring_sndcard,notify_end_of_ring,(void *)lc); + MSSndCard *ringcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.ring_sndcard; + lc->ringstream=ring_start_with_cb(ring,2000,ringcard,notify_end_of_ring,(void *)lc); } return 0; } diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index a7f8cfaea..0df37b800 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -31,15 +31,6 @@ typedef struct _LinphoneSoundDaemon LinphoneSoundDaemon; typedef void (*LsdEndOfPlayCallback)(LsdPlayer *p); -LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname); - -LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd); -void linphone_sound_daemon_release_player(LinphoneSoundDaemon *lsd, LsdPlayer *lsdplayer); - -struct _MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *obj); - -void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj); - void lsd_player_set_callback(LsdPlayer *p, LsdEndOfPlayCallback cb); void lsd_player_set_user_pointer(LsdPlayer *p, void *up); void *lsd_player_get_user_pointer(LsdPlayer *p); @@ -48,4 +39,10 @@ int lsd_player_stop(LsdPlayer *p); void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode); void lsd_player_set_gain(LsdPlayer *p, float gain); +LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname); +LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd); +void linphone_sound_daemon_release_player(LinphoneSoundDaemon *lsd, LsdPlayer *lsdplayer); +void linphone_core_use_sound_daemon(LinphoneCore *lc, LinphoneSoundDaemon *lsd); +void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj); + #endif diff --git a/coreapi/lsd.c b/coreapi/lsd.c index cb0f0af46..0ed782fe2 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "linphonecore_utils.h" +#include "private.h" #include "mediastreamer2/msticker.h" #include "mediastreamer2/mssndcard.h" #include "mediastreamer2/msaudiomixer.h" @@ -31,6 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/msitc.h" +static struct _MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *obj); #define MAX_BRANCHES 10 @@ -77,7 +79,7 @@ static MSSndCardDesc proxycard={ LsdPlayer *linphone_sound_daemon_get_player(LinphoneSoundDaemon *obj){ int i; - for(i=0;ibranches[i]; MSFilter *p=b->player; int state; @@ -174,8 +176,6 @@ int lsd_player_play(LsdPlayer *b, const char *filename ){ return 0; } -int lsd_player_stop(LsdPlayer *p); - void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode){ if (ms_filter_get_id(p->player)==MS_FILE_PLAYER_ID){ int arg=loopmode ? 0 : -1; @@ -252,8 +252,10 @@ void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj){ ms_filter_destroy(obj->itcsink); } - - MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *lsd){ return lsd->proxycard; } + +void linphone_core_use_sound_daemon(LinphoneCore *lc, LinphoneSoundDaemon *lsd){ + lc->sound_conf.lsd_card=linphone_sound_daemon_get_proxy_card (lsd); +} diff --git a/coreapi/private.h b/coreapi/private.h index c3e2960a3..22286987e 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -293,6 +293,7 @@ typedef struct sound_config struct _MSSndCard * ring_sndcard; /* the playback sndcard currently used */ struct _MSSndCard * play_sndcard; /* the playback sndcard currently used */ struct _MSSndCard * capt_sndcard; /* the capture sndcard currently used */ + struct _MSSndCard * lsd_card; /* dummy playback card for Linphone Sound Daemon extension */ const char **cards; int latency; /* latency in samples of the current used sound device */ char rec_lev; From 7fa19445c215e1146078e5dba8bc49bc942e35e9 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 30 May 2010 22:40:19 +0200 Subject: [PATCH 5/6] improved test with new event queue --- coreapi/Makefile.am | 5 ++ coreapi/linphonecore.c | 24 ++++++--- coreapi/linphonecore_utils.h | 4 +- coreapi/lsd.c | 19 ++++++- coreapi/private.h | 1 + coreapi/test_lsd.c | 102 +++++++++++++++++++++++++++++++++++ 6 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 coreapi/test_lsd.c diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 66a2bf5f6..44f7532a8 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -49,6 +49,11 @@ if BUILD_WIN32 liblinphone_la_LIBADD+=$(top_builddir)/oRTP/src/libortp.la endif +noinst_PROGRAMS=test_lsd + +test_lsd_SOURCES=test_lsd.c + +test_lsd_LDADD=liblinphone.la AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE \ $(ORTP_CFLAGS) \ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index d6df2f81a..822dc169a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/mediastream.h" #include "mediastreamer2/msvolume.h" #include "mediastreamer2/msequalizer.h" +#include "mediastreamer2/mseventqueue.h" #include @@ -631,6 +632,11 @@ static void sip_config_read(LinphoneCore *lc) int port; int i,tmp; int ipv6; + + if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){ + sal_use_session_timers(lc->sal,200); + } + port=lp_config_get_int(lc->config,"sip","use_info",0); linphone_core_set_use_info_for_dtmf(lc,port); @@ -641,7 +647,8 @@ static void sip_config_read(LinphoneCore *lc) if (ipv6==-1){ ipv6=0; if (host_has_ipv6_network()){ - lc->vtable.display_message(lc,_("Your machine appears to be connected to an IPv6 network. By default linphone always uses IPv4. Please update your configuration if you want to use IPv6")); + if (lc->vtable.display_message) + lc->vtable.display_message(lc,_("Your machine appears to be connected to an IPv6 network. By default linphone always uses IPv4. Please update your configuration if you want to use IPv6")); } } linphone_core_enable_ipv6(lc,ipv6); @@ -1078,6 +1085,10 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta #endif ms_init(); + /* create a mediastreamer2 event queue and set it as global */ + /* This allows to run event's callback in linphone_core_iterate() */ + lc->msevq=ms_event_queue_new(); + ms_set_global_event_queue(lc->msevq); lc->config=lp_config_new(config_path); if (factory_config_path) @@ -1086,9 +1097,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta lc->sal=sal_init(); sal_set_user_pointer(lc->sal,lc); sal_set_callbacks(lc->sal,&linphone_sal_callbacks); - if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){ - sal_use_session_timers(lc->sal,200); - } + sip_setup_register_all(); sound_config_read(lc); net_config_read(lc); @@ -1101,8 +1110,9 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta lc->presence_mode=LINPHONE_STATUS_ONLINE; lc->max_call_logs=15; ui_config_read(lc); - lc->vtable.display_status(lc,_("Ready")); - gstate_new_state(lc, GSTATE_POWER_ON, NULL); + if (lc->vtable.display_status) + lc->vtable.display_status(lc,_("Ready")); + gstate_new_state(lc, GSTATE_POWER_ON, NULL); lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; lc->ready=TRUE; @@ -1667,6 +1677,7 @@ void linphone_core_iterate(LinphoneCore *lc){ } sal_iterate(lc->sal); + ms_event_queue_pump(lc->msevq); if (lc->auto_net_state_mon) monitor_network_state(lc,curtime); proxy_update(lc); @@ -3593,6 +3604,7 @@ static void linphone_core_uninit(LinphoneCore *lc) lc->previewstream=NULL; } #endif + ms_event_queue_destroy(lc->msevq); /* save all config */ net_config_uninit(lc); sip_config_uninit(lc); diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index 0df37b800..43d6559bd 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -33,11 +33,13 @@ typedef void (*LsdEndOfPlayCallback)(LsdPlayer *p); void lsd_player_set_callback(LsdPlayer *p, LsdEndOfPlayCallback cb); void lsd_player_set_user_pointer(LsdPlayer *p, void *up); -void *lsd_player_get_user_pointer(LsdPlayer *p); +void *lsd_player_get_user_pointer(const LsdPlayer *p); int lsd_player_play(LsdPlayer *p, const char *filename); int lsd_player_stop(LsdPlayer *p); void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode); +bool_t lsd_player_loop_enabled(const LsdPlayer *p); void lsd_player_set_gain(LsdPlayer *p, float gain); +LinphoneSoundDaemon lsd_player_get_daemon(const LsdPlayer *p); LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname); LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd); diff --git a/coreapi/lsd.c b/coreapi/lsd.c index 0ed782fe2..2dd9898a5 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -45,6 +45,8 @@ struct _LsdPlayer{ LsdEndOfPlayCallback eop_cb; int mixer_pin; void *user_data; + bool_t loop; + bool_t pad[3]; }; struct _LinphoneSoundDaemon { @@ -86,6 +88,7 @@ LsdPlayer *linphone_sound_daemon_get_player(LinphoneSoundDaemon *obj){ ms_filter_call_method(p,MS_PLAYER_GET_STATE,&state); if (state==MSPlayerClosed){ lsd_player_set_gain(b,1); + lsd_player_enable_loop (b,FALSE); return b; } } @@ -118,6 +121,7 @@ static void lsd_player_init(LsdPlayer *p, MSConnectionPoint mixer, MSFilterId pl ms_connection_helper_link(&h,p->chanadapter,0,0); ms_connection_helper_link(&h,mixer.filter,mixer.pin,-1); p->mixer_pin=mixer.pin; + p->loop=FALSE; p->lsd=lsd; } @@ -143,11 +147,14 @@ void lsd_player_set_user_pointer(LsdPlayer *p, void *up){ p->user_data=up; } -void *lsd_player_get_user_pointer(LsdPlayer *p){ +void *lsd_player_get_user_pointer(const LsdPlayer *p){ return p->user_data; } static void lsd_player_on_eop(void * userdata, unsigned int id, void *arg){ + LsdPlayer *p=(LsdPlayer *)userdata; + if (p->eop_cb!=NULL) + p->eop_cb(p); } int lsd_player_play(LsdPlayer *b, const char *filename ){ @@ -161,6 +168,7 @@ int lsd_player_play(LsdPlayer *b, const char *filename ){ } if (ms_filter_call_method(b->player,MS_PLAYER_OPEN,(void*)filename)!=0){ + ms_warning("Could not play %s",filename); return -1; } ms_filter_call_method(b->player,MS_FILTER_GET_SAMPLE_RATE,&rate); @@ -173,6 +181,7 @@ int lsd_player_play(LsdPlayer *b, const char *filename ){ ms_filter_call_method(b->chanadapter,MS_FILTER_SET_NCHANNELS,&chans); ms_filter_call_method(b->chanadapter,MS_CHANNEL_ADAPTER_SET_OUTPUT_NCHANNELS,&lsd->out_nchans); + ms_filter_call_method_noarg (b->player,MS_PLAYER_START); return 0; } @@ -180,9 +189,14 @@ void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode){ if (ms_filter_get_id(p->player)==MS_FILE_PLAYER_ID){ int arg=loopmode ? 0 : -1; ms_filter_call_method(p->player,MS_FILE_PLAYER_LOOP,&arg); + p->loop=loopmode; } } +bool_t lsd_player_loop_enabled(const LsdPlayer *p){ + return p->loop; +} + void lsd_player_set_gain(LsdPlayer *p, float gain){ MSAudioMixerCtl gainctl; gainctl.pin=p->mixer_pin; @@ -220,7 +234,7 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ mp.filter=lsd->mixer; mp.pin=0; - lsd_player_init(&lsd->branches[0],mp,MS_ITC_SINK_ID,lsd); + lsd_player_init(&lsd->branches[0],mp,MS_ITC_SOURCE_ID,lsd); for(i=1;ibranches[i],mp,MS_FILE_PLAYER_ID,lsd); @@ -246,6 +260,7 @@ void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj){ mp.pin=i; lsd_player_uninit (&obj->branches[i],mp); } + ms_filter_unlink(obj->mixer,0,obj->soundout,0); ms_ticker_destroy(obj->ticker); ms_filter_destroy(obj->soundout); ms_filter_destroy(obj->mixer); diff --git a/coreapi/private.h b/coreapi/private.h index 22286987e..7a4c42052 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -371,6 +371,7 @@ struct _LinphoneCore struct _AudioStream *audiostream; /**/ struct _VideoStream *videostream; struct _VideoStream *previewstream; + struct _MSEventQueue *msevq; RtpTransport *a_rtp,*a_rtcp; MSList *bl_reqs; MSList *subscribers; /* unknown subscribers */ diff --git a/coreapi/test_lsd.c b/coreapi/test_lsd.c new file mode 100644 index 000000000..64b5d8a78 --- /dev/null +++ b/coreapi/test_lsd.c @@ -0,0 +1,102 @@ +/* +linphone +Copyright (C) 2010 Simon MORLAT (simon.morlat@linphone.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* Linphone Sound Daemon: is a lightweight utility to play sounds to speaker during a conversation. + This is useful for embedded platforms, where sound apis are not performant enough to allow + simultaneous sound access. + + This file is a test program that plays several sound files and places a call simultatenously. +*/ + +#include "linphonecore_utils.h" + +static void play_finished(LsdPlayer *p){ + const char *filename=(const char *)lsd_player_get_user_pointer (p); + ms_message("Playing of %s is finished.",filename); + if (!lsd_player_loop_enabled (p)){ + linphone_sound_daemon_release_player (lsd_player_get_daemon(p)); + } +} + +static void wait_a_bit(LinphoneCore *lc, int seconds){ + time_t orig=time(NULL); + while(time(NULL)-orig1){ + linphone_core_invite(lc,argv[1]); + wait_a_bit(lc,10); + linphone_core_terminate_call(lc,NULL); + } + + linphone_core_destroy(lc); + linphone_sound_daemon_destroy(lsd); + return 0; +} From 9bd55d0b34286d55e89a9c2df61c774f1b4d53aa Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 31 May 2010 16:54:40 +0200 Subject: [PATCH 6/6] bugfixing in lsd. --- coreapi/callbacks.c | 6 +- coreapi/exevents.c | 1189 ---------------------------------- coreapi/linphonecore.c | 36 +- coreapi/linphonecore.h | 2 +- coreapi/linphonecore_utils.h | 2 +- coreapi/lsd.c | 8 +- coreapi/presence.c | 3 +- coreapi/test_lsd.c | 2 +- 8 files changed, 38 insertions(+), 1210 deletions(-) delete mode 100644 coreapi/exevents.c diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index a4ce8e341..6f86c9bbb 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -249,8 +249,10 @@ static void call_terminated(SalOp *op, const char *from){ lc->ringstream=NULL; } linphone_core_stop_media_streams(lc,lc->call); - lc->vtable.show(lc); - lc->vtable.display_status(lc,_("Call terminated.")); + if (lc->vtable.show!=NULL) + lc->vtable.show(lc); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,_("Call terminated.")); gstate_new_state(lc, GSTATE_CALL_END, NULL); if (lc->vtable.bye_recv!=NULL){ LinphoneAddress *addr=linphone_address_new(from); diff --git a/coreapi/exevents.c b/coreapi/exevents.c deleted file mode 100644 index 24e830905..000000000 --- a/coreapi/exevents.c +++ /dev/null @@ -1,1189 +0,0 @@ -/* -linphone -Copyright (C) 2000 Simon MORLAT (simon.morlat@free.fr) - -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 "exevents.h" -#include "linphonecore.h" -#include "private.h" -#include "mediastreamer2/mediastream.h" -#include -#include -#include - -static int linphone_answer_sdp(LinphoneCore *lc, eXosip_event_t *ev, sdp_message_t *sdp); - -static bool_t linphone_call_matches_event(LinphoneCall *call, eXosip_event_t *ev){ - return call->cid==ev->cid; -} - -static void linphone_call_proceeding(LinphoneCore *lc, eXosip_event_t *ev){ - if (lc->call==NULL || (lc->call->cid!=-1 && !linphone_call_matches_event(lc->call,ev)) ) { - ms_warning("This call has been canceled: call=%p, call->cid=%i, ev->cid=%i", - lc->call,lc->call?lc->call->cid:-1,ev->cid); - eXosip_lock(); - eXosip_call_terminate(ev->cid,ev->did); - eXosip_unlock(); - return; - } - lc->call->cid=ev->cid; - lc->call->did=ev->did; - lc->call->tid=ev->tid; -} - -static void linphone_connect_incoming(LinphoneCore *lc){ - lc->vtable.show(lc); - lc->vtable.display_status(lc,_("Connected.")); - lc->call->state=LCStateAVRunning; - if (lc->ringstream!=NULL){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } - if (lc->audiostream->ticker!=NULL){ - /*case where we accepted early media */ - linphone_core_stop_media_streams(lc); - linphone_core_init_media_streams(lc); - } - linphone_core_start_media_streams(lc,lc->call); -} - -int linphone_call_accepted(LinphoneCore *lc, eXosip_event_t *ev) -{ - LinphoneCall *call=lc->call; - sdp_message_t *sdp; - const char *sdpanswer=NULL; - osip_message_t *msg=NULL; - int err; - if (call==NULL){ - ms_warning("No call to accept."); - return 0; - } - linphone_call_proceeding(lc,ev); - if (!linphone_call_matches_event(lc->call,ev)) return 0; - call->auth_pending=FALSE; - if (call->state==LCStateAVRunning){ - return 0; /*already accepted*/ - } - linphone_call_init_media_params(call); - sdp=eXosip_get_sdp_info(ev->response); - if (!lc->sip_conf.sdp_200_ack){ - err=0; - sdp_context_read_answer(call->sdpctx,sdp); - }else{ - /*we receive a 200OK with an sdp offer*/ - err=linphone_answer_sdp(lc,ev,sdp); - if (err==0) sdpanswer=call->sdpctx->answerstr; - } - if (err==0){ - gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); - linphone_connect_incoming(lc); - } - /*send the ack once streams are started*/ - eXosip_call_build_ack(ev->did,&msg); - if (sdpanswer!=NULL) linphone_set_sdp(msg,sdpanswer); - eXosip_call_send_ack(ev->did,msg); - if (err!=0){ - /*send a bye*/ - ms_error("Incompatible SDP offer received in 200Ok, need to abort the call"); - linphone_core_terminate_call(lc,NULL); - } - sdp_message_free(sdp); - return 0; -} - - -int linphone_call_terminated(LinphoneCore *lc, eXosip_event_t *ev) -{ - /*stop ringing if necessary*/ - if (lc->call!=NULL){ - if (lc->call->cid!=ev->cid){ - /* this is not current call */ - ms_message("call %i terminated, this was not current call.",ev->cid); - return 0; - } - } - - ms_message("Current call terminated..."); - if (lc->ringstream!=NULL) { - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } - linphone_core_stop_media_streams(lc); - lc->vtable.show(lc); - lc->vtable.display_status(lc,_("Call terminated.")); - gstate_new_state(lc, GSTATE_CALL_END, NULL); - if (lc->vtable.bye_recv!=NULL){ - char *from; - osip_from_to_str(ev->request->from,&from); - lc->vtable.bye_recv(lc,from); - osip_free(from); - } - if (lc->call!=NULL){ - linphone_call_destroy(lc->call); - lc->call=NULL; - } - return 0; -} - - -int linphone_call_released(LinphoneCore *lc, int cid){ - LinphoneCall *call=lc->call; - if (call!=NULL && call->cid==cid){ - - linphone_call_destroy(lc->call); - lc->call=NULL; - lc->vtable.display_status(lc,_("Could not reach destination.")); - gstate_new_state(lc, GSTATE_CALL_ERROR, NULL); - } - return 0; -} - -int linphone_call_failure(LinphoneCore *lc, eXosip_event_t *ev) -{ - const char *reason=""; - char *msg486=_("User is busy."); - char *msg480=_("User is temporarily unavailable."); - char *msg487=_("Request Cancelled."); - /*char *retrymsg=_("%s. Retry after %i minute(s).");*/ - char *msg600=_("User does not want to be disturbed."); - char *msg603=_("Call declined."); - char* tmpmsg=msg486; - int code; - LinphoneCall *call=lc->call; - - if (call){ - /*check that the faillure is related to this call, not an old one*/ - if (!linphone_call_matches_event(call,ev)) { - ms_warning("Failure reported for an old call."); - return 0; - } - } - - if (ev->response){ - code=osip_message_get_status_code(ev->response); - reason=osip_message_get_reason_phrase(ev->response); - }else code=-110; - lc->vtable.show(lc); - - switch(code) - { - case 401: - case 407: - if (lc->call!=NULL) - linphone_process_authentication(lc,ev); - return 0; - break; - case 400: - lc->vtable.display_status(lc,_("Bad request")); - break; - case 404: - lc->vtable.display_status(lc,_("User cannot be found at given address.")); - break; - case 415: - lc->vtable.display_status(lc,_("Remote user cannot support any of proposed codecs.")); - break; - case 422: - /*ignore: eXosip_automatic_action will do the job of retrying with a greater Session-Expires*/ - return 0; - break; - case 480: - tmpmsg=msg480; - case 486: - /* - msg_header_getbyname(msg,"retry-after",0,&retry); - if (retry!=NULL) - { - umsg=g_malloc(strlen(tmpmsg)+strlen(retrymsg)+13); - sprintf(umsg,retrymsg,tmpmsg,atoi(retry->hvalue)/60); - lc->vtable.display_message(lc,umsg); - ms_free(umsg); - }*/ - lc->vtable.display_message(lc,tmpmsg); - break; - case 487: /*request terminated*/ - lc->vtable.display_status(lc,msg487); - break; - case 600: - lc->vtable.display_message(lc,msg600); - break; - case 603: - lc->vtable.display_status(lc,msg603); - break; - case -110: /* time out, call leg is lost */ - lc->vtable.display_status(lc,_("Timeout.")); - break; - case -111: - lc->vtable.display_status(lc,_("Remote host was found but refused connection.")); - break; - - default: - if (code>0) - { - lc->vtable.display_status(lc,reason); - } - else ms_warning("failure_cb unknown code=%i\n",code); - } - if (lc->ringstream!=NULL) { - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } - linphone_core_stop_media_streams(lc); - if (call!=NULL) { - linphone_call_destroy(call); - gstate_new_state(lc, GSTATE_CALL_ERROR, NULL); - lc->call=NULL; - } - return 0; -} - -extern sdp_handler_t linphone_sdphandler; - -static int linphone_answer_sdp(LinphoneCore *lc, eXosip_event_t *ev, sdp_message_t *sdp){ - int status=200; - sdp_context_t *ctx=NULL; - - ctx=lc->call->sdpctx; - /* get the result of the negociation */ - sdp_context_get_answer(ctx,sdp); - status=sdp_context_get_status(ctx); - - if (status==200){ - linphone_core_init_media_streams(lc); - return 0; - }else{ - if (status==-1) status=415; - } - return -1; -} - -int linphone_inc_new_call(LinphoneCore *lc, eXosip_event_t *ev) -{ - sdp_message_t *sdp=NULL; - osip_from_t *from_url=ev->request->from; - char *barmesg; - char *from; - char *to; - int err; - - osip_from_to_str(ev->request->from,&from); - osip_to_to_str(ev->request->to,&to); - - /* first check if we can answer successfully to this invite */ - if (lc->presence_mode!=LINPHONE_STATUS_ONLINE){ - ms_message("Not present !! presence mode : %d\n",lc->presence_mode); - eXosip_lock(); - if (lc->presence_mode==LINPHONE_STATUS_BUSY) - eXosip_call_send_answer(ev->tid,486,NULL); - else if (lc->presence_mode==LINPHONE_STATUS_AWAY - ||lc->presence_mode==LINPHONE_STATUS_BERIGHTBACK - ||lc->presence_mode==LINPHONE_STATUS_ONTHEPHONE - ||lc->presence_mode==LINPHONE_STATUS_OUTTOLUNCH - ||lc->presence_mode==LINPHONE_STATUS_OFFLINE) - eXosip_call_send_answer(ev->tid,480,NULL); - else if (lc->presence_mode==LINPHONE_STATUS_NOT_DISTURB) - eXosip_call_send_answer(ev->tid,480,NULL); - else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_MOVED) - { - osip_message_t *msg; - eXosip_call_build_answer(ev->tid,302,&msg); - osip_message_set_contact(msg,lc->alt_contact); - eXosip_call_send_answer(ev->tid,302,msg); - } - else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_ALT_SERVICE) - { - osip_message_t *msg; - eXosip_call_build_answer(ev->tid,380,&msg); - osip_message_set_contact(msg,lc->alt_contact); - eXosip_call_send_answer(ev->tid,380,msg); - } - else - eXosip_call_send_answer(ev->tid,486,NULL); - eXosip_unlock(); - goto end; - } - if (lc->call!=NULL){/*busy*/ - eXosip_lock(); - eXosip_call_send_answer(ev->tid,486,NULL); - eXosip_unlock(); - goto end; - } - lc->call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),ev); - - sdp=eXosip_get_sdp_info(ev->request); - if (sdp==NULL){ - ms_message("No sdp body in invite, 200-ack scheme"); - err=0; - }else{ - err=linphone_answer_sdp(lc,ev,sdp); - } - if (!err){ - char *tmp; - if (from_2char_without_params(from_url,&tmp)!=0){ - tmp=ms_strdup("Unknown user"); - } - gstate_new_state(lc, GSTATE_CALL_IN_INVITE, tmp); - barmesg=ortp_strdup_printf("%s %s",tmp,_("is contacting you.")); - lc->vtable.show(lc); - lc->vtable.display_status(lc,barmesg); - - /* play the ring */ - if (lc->sound_conf.ring_sndcard!=NULL){ - ms_message("Starting local ring..."); - lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard); - } - linphone_call_set_state(lc->call,LCStateRinging); - eXosip_lock(); - eXosip_call_send_answer(ev->tid,180,NULL); - eXosip_unlock(); - - lc->vtable.inv_recv(lc,tmp); - ms_free(barmesg); - osip_free(tmp); - }else{ - ms_error("Error during sdp negociation. "); - eXosip_lock(); - eXosip_call_send_answer(ev->tid,415,NULL); - eXosip_unlock(); - linphone_call_destroy(lc->call); - lc->call=NULL; - } - end: - osip_free(from); - osip_free(to); - if (sdp) sdp_message_free(sdp); - return 0; -} - -void linphone_handle_ack(LinphoneCore *lc, eXosip_event_t *ev){ - sdp_message_t *sdp=eXosip_get_sdp_info(ev->ack); - if (sdp){ - sdp_context_read_answer(lc->call->sdpctx,sdp); - linphone_connect_incoming(lc); - sdp_message_free(sdp); - } -} - -void linphone_handle_reinvite(LinphoneCore *lc, eXosip_event_t *ev){ - sdp_message_t *sdp=eXosip_get_sdp_info(ev->request); - sdp_context_t *ctx; - LinphoneCall *call=lc->call; - char *answer; - int status; - if (sdp==NULL){ - ms_warning("No sdp in reinvite !"); - eXosip_lock(); - eXosip_call_send_answer(ev->tid,603,NULL); - eXosip_unlock(); - return; - } - ctx=call->sdpctx; - /* get the result of the negociation */ - linphone_call_init_media_params(call); - answer=sdp_context_get_answer(ctx,sdp); - status=sdp_context_get_status(ctx); - if (status==200){ - osip_message_t *msg=NULL; - linphone_core_stop_media_streams(lc); - linphone_core_init_media_streams(lc); - eXosip_lock(); - if (eXosip_call_build_answer(ev->tid,200,&msg)<0){ - ms_warning("Reinvite for closed call ?"); - eXosip_unlock(); - linphone_core_stop_media_streams(lc); - sdp_message_free(sdp); - return ; - } - answer=call->sdpctx->answerstr; /* takes the sdp already computed*/ - linphone_set_sdp(msg,answer); - eXosip_call_send_answer(ev->tid,200,msg); - eXosip_unlock(); - linphone_core_start_media_streams(lc,call); - }else{ - eXosip_lock(); - eXosip_call_send_answer(ev->tid,status,NULL); - eXosip_unlock(); - } - sdp_message_free(sdp); -} - -void linphone_do_automatic_redirect(LinphoneCore *lc, const char *contact){ - char *msg=ortp_strdup_printf(_("Redirected to %s..."),contact); - lc->vtable.display_status(lc,msg); - ms_free(msg); - if (lc->call!=NULL) linphone_call_destroy(lc->call); - lc->call=NULL; - linphone_core_invite(lc,contact); -} - -void linphone_call_redirected(LinphoneCore *lc, eXosip_event_t *ev){ - int code=osip_message_get_status_code(ev->response); - char *contact=NULL; - osip_contact_t *ct; - osip_message_get_contact(ev->response,0,&ct); - if (ct) osip_contact_to_str(ct,&contact); - switch(code){ - case 380: - lc->vtable.display_url(lc,_("User is not reachable at the moment but he invites you\nto contact him using the following alternate resource:"),contact); - if (lc->call!=NULL) linphone_call_destroy(lc->call); - lc->call=NULL; - break; - case 302: - linphone_do_automatic_redirect(lc,contact); - break; - } - if (contact) osip_free(contact); -} - - -/* these are the SdpHandler callbacks: we are called in to be aware of the content -of the SDP messages exchanged */ - -int linphone_set_audio_offer(sdp_context_t *ctx) -{ - LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); - LinphoneCore *lc=call->core; - PayloadType *codec; - MSList *elem; - sdp_payload_t payload; - - - elem=lc->codecs_conf.audio_codecs; - while(elem!=NULL){ - codec=(PayloadType*) elem->data; - if (linphone_core_check_payload_type_usability(lc,codec) && - linphone_core_payload_type_enabled(lc,codec)){ - sdp_payload_init(&payload); - payload.a_rtpmap=ortp_strdup_printf("%s/%i/1",codec->mime_type,codec->clock_rate); - payload.pt=rtp_profile_get_payload_number_from_rtpmap(lc->local_profile,payload.a_rtpmap); - payload.localport=call->audio_params.natd_port > 0 ? - call->audio_params.natd_port : lc->rtp_conf.audio_rtp_port; - sdp_context_add_audio_payload(ctx,&payload); - ms_free(payload.a_rtpmap); - } - elem=ms_list_next(elem); - } - /* add telephone-event payload*/ - sdp_payload_init(&payload); - payload.pt=rtp_profile_get_payload_number_from_mime(lc->local_profile,"telephone-event"); - payload.a_rtpmap="telephone-event/8000"; - payload.a_fmtp="0-11"; - if (lc->dw_audio_bw>0) payload.b_as_bandwidth=lc->dw_audio_bw; - if (lc->down_ptime>0) { - payload.a_ptime=lc->down_ptime; - ms_message("ptime [%i]",payload.a_ptime); - } - sdp_context_add_audio_payload(ctx,&payload); - return 0; -} - -static int find_payload_type_number(RtpProfile *prof, PayloadType *pt){ - int candidate=-1,i; - PayloadType *it; - for(i=0;i<127;++i){ - it=rtp_profile_get_payload(prof,i); - if (it!=NULL && strcasecmp(pt->mime_type,it->mime_type)==0 - && (pt->clock_rate==it->clock_rate || pt->clock_rate<=0) ){ - if ( (pt->recv_fmtp && it->recv_fmtp && strcasecmp(pt->recv_fmtp,it->recv_fmtp)==0) || - (pt->recv_fmtp==NULL && it->recv_fmtp==NULL) ){ - /*exact match*/ - return i; - }else candidate=i; - } - } - if (candidate==-1) ms_fatal("Should not happen."); - return candidate; -} - -static int find_payload_type_number_best_match(RtpProfile *prof, const char *rtpmap, const char *fmtp){ - int localpt=rtp_profile_get_payload_number_from_rtpmap(prof,rtpmap); - PayloadType *pt; - char value[10]; - if (localpt<0) return -1; - pt=rtp_profile_get_payload(prof,localpt); - if (strcasecmp(pt->mime_type,"H264")==0){ - /*hack for H264: need to answer with same packetization-mode*/ - PayloadType tmp; - memset(&tmp,0,sizeof(tmp)); - tmp.mime_type="H264"; - tmp.clock_rate=pt->clock_rate; - if (fmtp && fmtp_get_value(fmtp,"packetization-mode",value,sizeof(value))){ - tmp.recv_fmtp=(atoi(value)==1) ? "packetization-mode=1" : NULL; - } - localpt=find_payload_type_number(prof,&tmp); - } - return localpt; -} - -int linphone_set_video_offer(sdp_context_t *ctx) -{ - LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); - LinphoneCore *lc=call->core; - PayloadType *codec; - MSList *elem; - bool_t firsttime=TRUE; - - if (!linphone_core_video_enabled(lc)) return -1; - - for(elem=lc->codecs_conf.video_codecs;elem!=NULL;elem=ms_list_next(elem)){ - codec=(PayloadType*) elem->data; - if (linphone_core_check_payload_type_usability(lc,codec) && - linphone_core_payload_type_enabled(lc,codec)){ - sdp_payload_t payload; - sdp_payload_init(&payload); - payload.line=1; - payload.a_rtpmap=ortp_strdup_printf("%s/%i",codec->mime_type,codec->clock_rate); - payload.localport=call->video_params.natd_port>0 ? - call->video_params.natd_port : lc->rtp_conf.video_rtp_port; - payload.pt=find_payload_type_number(lc->local_profile,codec); - payload.a_fmtp=codec->recv_fmtp; - if(firsttime){ - firsttime=FALSE; - if (lc->dw_video_bw>0) - payload.b_as_bandwidth=lc->dw_video_bw; - } - sdp_context_add_video_payload(ctx,&payload); - ms_free(payload.a_rtpmap); - } - } - return 0; -} - -typedef enum { - Unsupported, - Supported, - SupportedAndValid /* valid= the presence of this codec is enough to make a call */ -}SupportLevel; - -SupportLevel linphone_payload_is_supported(LinphoneCore *lc, sdp_payload_t *payload,RtpProfile *local_profile,RtpProfile *dialog_profile, bool_t answering, PayloadType **local_payload_type) -{ - int localpt; - SupportLevel ret; - if (payload->a_rtpmap!=NULL){ - localpt=find_payload_type_number_best_match(local_profile,payload->a_rtpmap,payload->a_fmtp); - }else{ - localpt=payload->pt; - ms_warning("payload has no rtpmap."); - } - - if (localpt>=0 && localpt <128 ){ - /* this payload is understood, but does the user want to use it ?? */ - PayloadType *rtppayload; - rtppayload=rtp_profile_get_payload(local_profile,localpt); - if (rtppayload==NULL) { - ms_warning("strange error !!"); - return Unsupported; - } - *local_payload_type=rtppayload; - if (strcmp(rtppayload->mime_type,"telephone-event")!=0){ - if (answering && !linphone_core_check_payload_type_usability(lc,rtppayload) ){ - ms_warning("payload %s is not usable",rtppayload->mime_type); - return Unsupported; - } - if ( !linphone_core_payload_type_enabled(lc,rtppayload)) { - ms_warning("payload %s is not enabled.",rtppayload->mime_type); - return Unsupported; - } - ret=SupportedAndValid; - }else ret=Supported; - if (dialog_profile!=NULL){ - int dbw,ubw; - /* this payload is supported in our local rtp profile, so add it to the dialog rtp - profile */ - rtppayload=payload_type_clone(rtppayload); - if (rtp_profile_get_payload(dialog_profile,payload->pt)!=NULL){ - ms_error("Payload %s type already entered, should not happen !",rtppayload->mime_type); - } - rtp_profile_set_payload(dialog_profile,payload->pt,rtppayload); - /* add to the rtp payload type some other parameters (bandwidth) */ - if (rtppayload->type==PAYLOAD_VIDEO){ - dbw=lc->dw_video_bw; - ubw=lc->up_video_bw; - }else{ - dbw=lc->dw_audio_bw; - ubw=lc->up_audio_bw; - } - if (payload->b_as_bandwidth!=0){ - ms_message("Remote bandwidth constraint: %i",payload->b_as_bandwidth); - /*obey to remote bandwidth constraint AND our own upbandwidth constraint*/ - rtppayload->normal_bitrate=1000*get_min_bandwidth( - payload->b_as_bandwidth, ubw); - }else{ - /*limit to upload bandwidth if exist, else no limit*/ - if (ubw>0) rtppayload->normal_bitrate=1000*ubw; - else { - if (rtppayload->type!=PAYLOAD_VIDEO){ - rtppayload->normal_bitrate=-1; /*allow speex to use maximum bitrate*/ - } - } - } - if (payload->a_fmtp!=NULL){ - payload_type_set_send_fmtp(rtppayload,payload->a_fmtp); - } - payload->a_fmtp=rtppayload->recv_fmtp; - if (payload->a_ptime>0){ - char tmp[30]; - snprintf(tmp,sizeof(tmp),"ptime=%i",payload->a_ptime); - payload_type_append_send_fmtp(rtppayload,tmp); - ms_message("%s attribute added to fmtp",tmp); - } - } - return ret; - } - return Unsupported; -} - -int linphone_accept_audio_offer(sdp_context_t *ctx,sdp_payload_t *payload) -{ - RtpProfile *remote_profile; - StreamParams *params; - SupportLevel supported; - LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); - LinphoneCore *lc=call->core; - PayloadType *lpt=NULL; - - params=&call->audio_params; - remote_profile=call->profile; - /* see if this codec is supported in our local rtp profile*/ - supported=linphone_payload_is_supported(lc,payload,lc->local_profile,remote_profile,TRUE,&lpt); - if (supported==Unsupported) { - ms_message("Refusing audio codec %i (%s)",payload->pt,payload->a_rtpmap); - return -1; - } - if (lc->sip_conf.only_one_codec && params->initialized){ - ms_message("Only one codec has to be accepted."); - return -1; - } - if (supported==SupportedAndValid) { - if (params->initialized==0){ - /* this is the first codec we accept, it is going to be used*/ - params->localport=lc->rtp_conf.audio_rtp_port; - payload->localport=params->natd_port>0 ? - params->natd_port : lc->rtp_conf.audio_rtp_port; - params->line=payload->line; - params->pt=payload->pt; /* remember the first payload accepted */ - if (payload->relay_host!=NULL){ - strncpy(params->remoteaddr,payload->relay_host,sizeof(params->remoteaddr)-1); - params->remoteport=payload->relay_port; - params->remotertcpport=payload->relay_port; - params->relay_session_id=payload->relay_session_id; - }else{ - strncpy(params->remoteaddr,payload->c_addr,sizeof(params->remoteaddr)-1); - params->remoteport=payload->remoteport; - params->remotertcpport=payload->remoteport+1; - } - params->initialized=1; - /* we can now update the allocated bandwidth for audio, and then video*/ - linphone_core_update_allocated_audio_bandwidth_in_call(lc,lpt); - /* give our download bandwidth constraint*/ - payload->b_as_bandwidth=(lc->dw_audio_bw>0) ? lc->dw_audio_bw : 0; - }else{ - /* refuse all other audio lines*/ - if(params->line!=payload->line) { - ms_message("Only one audio line can be accepted."); -#if !defined(_WIN32_WCE) - abort(); -#endif /*_WIN32_WCE*/ - return -1; - } - } - } - return 0; -} - -int linphone_accept_video_offer(sdp_context_t *ctx,sdp_payload_t *payload) -{ - LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); - LinphoneCore *lc=call->core; - RtpProfile *remote_profile; - StreamParams *params; - SupportLevel supported; - PayloadType *lpt=NULL; - - if (!linphone_core_video_enabled(lc)) return -1; - - if (payload->remoteport==0) { - ms_message("Video stream refused by remote."); - return 0; - } - - params=&call->video_params; - remote_profile=call->profile; - /* see if this codec is supported in our local rtp profile*/ - supported=linphone_payload_is_supported(lc,payload,lc->local_profile,remote_profile,TRUE,&lpt); - if (supported==Unsupported) { - ms_message("Refusing video codec %i (%s)",payload->pt,payload->a_rtpmap); - return -1; - } - if (lc->sip_conf.only_one_codec && params->initialized){ - return -1; - } - if (supported==SupportedAndValid){ - if (params->initialized==0){ - /* this is the first codec we may accept*/ - params->localport=lc->rtp_conf.video_rtp_port; - payload->localport=params->natd_port>0 ? params->natd_port : lc->rtp_conf.video_rtp_port; - params->line=payload->line; - params->pt=payload->pt; /* remember the first payload accepted */ - if (payload->relay_host!=NULL){ - strncpy(params->remoteaddr,payload->relay_host,sizeof(params->remoteaddr)-1); - params->remoteport=payload->relay_port; - params->remotertcpport=payload->relay_port; - params->relay_session_id=payload->relay_session_id; - }else{ - strncpy(params->remoteaddr,payload->c_addr,sizeof(params->remoteaddr)-1); - params->remoteport=payload->remoteport; - params->remotertcpport=params->remoteport+1; - } - params->initialized=1; - payload->b_as_bandwidth=(lc->dw_video_bw>0) ? lc->dw_video_bw : 0; - }else{ - /* refuse all other video lines*/ - if(params->line!=payload->line) return -1; - } - } - return 0; -} - -int linphone_read_audio_answer(sdp_context_t *ctx,sdp_payload_t *payload) -{ - LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); - LinphoneCore *lc=call->core; - StreamParams *params; - SupportLevel supported; - PayloadType *lpt=NULL; - - /* paranoid check: see if this codec is supported in our local rtp profile*/ - supported=linphone_payload_is_supported(lc, payload,lc->local_profile,call->profile,FALSE,&lpt); - if (supported==Unsupported) { - ms_warning("This remote sip phone did not answer properly to my sdp offer: rtpmap=%s",payload->a_rtpmap); - return 0; - } - if (supported==SupportedAndValid){ - params=&call->audio_params; - if (params->initialized==0){ - /* this is the first codec we accept, this is the one that is going to be used (at least for sending - data.*/ - params->localport=lc->rtp_conf.audio_rtp_port; - params->line=payload->line; - params->pt=payload->pt; /* remember the first payload accepted */ - if (payload->relay_host!=NULL){ - strncpy(params->remoteaddr,payload->relay_host,sizeof(params->remoteaddr)-1); - params->remoteport=payload->relay_port; - params->remotertcpport=payload->relay_port; - params->relay_session_id=payload->relay_session_id; - }else{ - strncpy(params->remoteaddr,payload->c_addr,sizeof(params->remoteaddr)-1); - params->remoteport=payload->remoteport; - params->remotertcpport=payload->remoteport+1; - } - params->initialized=1; - /* we can now update the allocated bandwidth for audio, and then video*/ - linphone_core_update_allocated_audio_bandwidth_in_call(lc,lpt); - } - } - return 0; -} - -int linphone_read_video_answer(sdp_context_t *ctx,sdp_payload_t *payload) -{ - LinphoneCall *call=(LinphoneCall*)sdp_context_get_user_pointer(ctx); - LinphoneCore *lc=call->core; - StreamParams *params; - SupportLevel supported; - PayloadType *lpt=NULL; - - /* paranoid check: see if this codec is supported in our local rtp profile*/ - supported=linphone_payload_is_supported(lc, payload,lc->local_profile,call->profile,FALSE,&lpt); - if (supported==Unsupported) { - ms_warning("This remote sip phone did not answer properly to my sdp offer: rtpmap=%s",payload->a_rtpmap); - return 0; - } - if (supported==SupportedAndValid){ - params=&call->video_params; - if (params->initialized==0){ - /* this is the first codec we may accept*/ - params->localport=lc->rtp_conf.video_rtp_port; - params->line=payload->line; - params->pt=payload->pt; /* remember the first payload accepted */ - if (payload->relay_host!=NULL){ - strncpy(params->remoteaddr,payload->relay_host,sizeof(params->remoteaddr)-1); - params->remoteport=payload->relay_port; - params->remotertcpport=payload->relay_port; - params->relay_session_id=payload->relay_session_id; - }else{ - strncpy(params->remoteaddr,payload->c_addr,sizeof(params->remoteaddr)-1); - params->remoteport=payload->remoteport; - params->remotertcpport=payload->remoteport+1; - } - params->initialized=1; - } - } - return 0; -} - -void linphone_call_ringing(LinphoneCore *lc, eXosip_event_t *ev){ - sdp_message_t *sdp=eXosip_get_sdp_info(ev->response); - LinphoneCall *call=lc->call; - - lc->vtable.display_status(lc,_("Remote ringing.")); - linphone_call_proceeding(lc,ev); - if (call==NULL) return; - if (sdp==NULL){ - if (lc->ringstream!=NULL) return; /*already ringing !*/ - if (lc->sound_conf.play_sndcard!=NULL){ - ms_message("Remote ringing..."); - lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,lc->sound_conf.play_sndcard); - } - }else{ - /*accept early media */ - StreamParams *audio_params; - if (call==NULL){ - ms_error("No call ?"); - goto end; - } - if (lc->audiostream->ticker!=NULL){ - /*streams already started */ - ms_message("Early media already started."); - goto end; - } - audio_params=&call->audio_params; - sdp_context_read_answer(lc->call->sdpctx,sdp); - lc->vtable.show(lc); - lc->vtable.display_status(lc,_("Early media.")); - gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL); - if (lc->ringstream!=NULL){ - ring_stop(lc->ringstream); - lc->ringstream=NULL; - } - ms_message("Doing early media..."); - linphone_core_start_media_streams(lc,call); - } - call->state=LCStateRinging; - goto end; - end: - sdp_message_free(sdp); - -} - -static void linphone_process_media_control_xml(LinphoneCore *lc, eXosip_event_t *ev){ - osip_body_t *body=NULL; - osip_message_get_body(ev->request,0,&body); - if (body && body->body!=NULL && - strstr(body->body,"picture_fast_update")){ - osip_message_t *ans=NULL; - ms_message("Receiving VFU request !"); -#ifdef VIDEO_ENABLED - if (lc->videostream) - video_stream_send_vfu(lc->videostream); -#endif - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - } -} - -static void linphone_process_dtmf_relay(LinphoneCore *lc, eXosip_event_t *ev){ - osip_body_t *body=NULL; - osip_message_get_body(ev->request,0,&body); - if (body && body->body!=NULL){ - osip_message_t *ans=NULL; - const char *name=strstr(body->body,"Signal"); - if (name==NULL) name=strstr(body->body,"signal"); - if (name==NULL) { - ms_warning("Could not extract the dtmf name from the SIP INFO."); - }else{ - char tmp[2]; - name+=strlen("signal"); - if (sscanf(name," = %1s",tmp)==1){ - ms_message("Receiving dtmf %s via SIP INFO.",tmp); - if (lc->vtable.dtmf_received != NULL) - lc->vtable.dtmf_received(lc, tmp[0]); - } - } - - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - } -} - -void linphone_call_message_new(LinphoneCore *lc, eXosip_event_t *ev){ - osip_message_t *ans=NULL; - if (ev->request){ - if (MSG_IS_INFO(ev->request)){ - osip_content_type_t *ct; - ct=osip_message_get_content_type(ev->request); - if (ct && ct->subtype){ - if (strcmp(ct->subtype,"media_control+xml")==0) - linphone_process_media_control_xml(lc,ev); - else if (strcmp(ct->subtype,"dtmf-relay")==0) - linphone_process_dtmf_relay(lc,ev); - else { - ms_message("Unhandled SIP INFO."); - /*send an "Not implemented" answer*/ - eXosip_call_build_answer(ev->tid,501,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,501,ans); - } - }else{ - /*empty SIP INFO, probably to test we are alive. Send an empty answer*/ - eXosip_call_build_answer(ev->tid,200,&ans); - if (ans) - eXosip_call_send_answer(ev->tid,200,ans); - } - } - }else ms_warning("linphone_call_message_new: No request ?"); -} - -void linphone_registration_faillure(LinphoneCore *lc, eXosip_event_t *ev){ - int status_code=0; - char *msg; - const char *reason=NULL; - osip_uri_t *requri=osip_message_get_uri(ev->request); - char *ru; - LinphoneProxyConfig *cfg; - - if (ev->response){ - status_code=osip_message_get_status_code(ev->response); - reason=osip_message_get_reason_phrase(ev->response); - } - switch(status_code){ - case 401: - case 407: - linphone_process_authentication(lc,ev); - break; - default: - cfg=linphone_core_get_proxy_config_from_rid(lc,ev->rid); - /* if contact is up to date, process the failure, otherwise resend a new register with - updated contact first, just in case the faillure is due to incorrect contact */ - if (linphone_proxy_config_register_again_with_updated_contact(cfg,ev->request,ev->response)) - return; /*we are retrying with an updated contact*/ - linphone_proxy_config_process_authentication_failure(lc,status_code,ev); - osip_uri_to_str(requri,&ru); - msg=ortp_strdup_printf(_("Registration on %s failed: %s"),ru,(reason!=NULL) ? reason : _("no response timeout")); - lc->vtable.display_status(lc,msg); - gstate_new_state(lc, GSTATE_REG_FAILED, msg); - ms_free(msg); - osip_free(ru); - } -} - -void linphone_registration_success(LinphoneCore *lc,eXosip_event_t *ev){ - LinphoneProxyConfig *cfg; - osip_uri_t *requri=osip_message_get_uri(ev->request); - char *msg; - char *ru; - osip_header_t *h=NULL; - - cfg=linphone_core_get_proxy_config_from_rid(lc,ev->rid); - ms_return_if_fail(cfg!=NULL); - - osip_message_get_expires(ev->request,0,&h); - if (h!=NULL && atoi(h->hvalue)!=0){ - cfg->registered=TRUE; - linphone_proxy_config_register_again_with_updated_contact(cfg,ev->request,ev->response); - }else cfg->registered=FALSE; - - gstate_new_state(lc, GSTATE_REG_OK, NULL); - - osip_uri_to_str(requri,&ru); - if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),ru); - else msg=ms_strdup_printf(_("Unregistration on %s done."),ru); - lc->vtable.display_status(lc,msg); - ms_free(msg); - osip_free(ru); -} - -static bool_t comes_from_local_if(osip_message_t *msg){ - osip_via_t *via=NULL; - osip_message_get_via(msg,0,&via); - if (via){ - const char *host; - host=osip_via_get_host(via); - if (strcmp(host,"127.0.0.1")==0 || strcmp(host,"::1")==0){ - osip_generic_param_t *param=NULL; - osip_via_param_get_byname(via,"received",¶m); - if (param==NULL) return TRUE; - if (param->gvalue && - (strcmp(param->gvalue,"127.0.0.1")==0 || strcmp(param->gvalue,"::1")==0)){ - return TRUE; - } - } - } - return FALSE; -} - -static void linphone_inc_update(LinphoneCore *lc, eXosip_event_t *ev){ - osip_message_t *msg=NULL; - ms_message("Processing incoming UPDATE"); - eXosip_lock(); - eXosip_message_build_answer(ev->tid,200,&msg); - if (msg!=NULL) - eXosip_message_send_answer(ev->tid,200,msg); - eXosip_unlock(); -} - -static void linphone_other_request(LinphoneCore *lc, eXosip_event_t *ev){ - ms_message("in linphone_other_request"); - if (ev->request==NULL) return; - if (strcmp(ev->request->sip_method,"MESSAGE")==0){ - linphone_core_text_received(lc,ev); - eXosip_message_send_answer(ev->tid,200,NULL); - }else if (strcmp(ev->request->sip_method,"OPTIONS")==0){ - osip_message_t *options=NULL; - eXosip_options_build_answer(ev->tid,200,&options); - osip_message_set_allow(options,"INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, SUBSCRIBE, NOTIFY, INFO"); - osip_message_set_accept(options,"application/sdp"); - eXosip_options_send_answer(ev->tid,200,options); - }else if (strcmp(ev->request->sip_method,"WAKEUP")==0 - && comes_from_local_if(ev->request)) { - eXosip_message_send_answer(ev->tid,200,NULL); - ms_message("Receiving WAKEUP request !"); - if (lc->vtable.show) - lc->vtable.show(lc); - }else if (strncmp(ev->request->sip_method, "REFER", 5) == 0){ - ms_message("Receiving REFER request !"); - if (comes_from_local_if(ev->request)) { - osip_header_t *h=NULL; - osip_message_header_get_byname(ev->request,"Refer-To",0,&h); - eXosip_message_send_answer(ev->tid,200,NULL); - if (h){ - if (lc->vtable.refer_received) - lc->vtable.refer_received(lc,h->hvalue); - } - - }else ms_warning("Ignored REFER not coming from this local loopback interface."); - }else if (strncmp(ev->request->sip_method, "UPDATE", 6) == 0){ - linphone_inc_update(lc,ev); - }else { - char *tmp=NULL; - size_t msglen=0; - osip_message_to_str(ev->request,&tmp,&msglen); - if (tmp){ - ms_message("Unsupported request received:\n%s",tmp); - osip_free(tmp); - } - /*answer with a 501 Not implemented*/ - eXosip_message_send_answer(ev->tid,501,NULL); - } -} - -void linphone_core_process_event(LinphoneCore *lc,eXosip_event_t *ev) -{ - switch(ev->type){ - case EXOSIP_CALL_ANSWERED: - ms_message("CALL_ANSWERED\n"); - linphone_call_accepted(lc,ev); - linphone_authentication_ok(lc,ev); - break; - case EXOSIP_CALL_CLOSED: - case EXOSIP_CALL_CANCELLED: - ms_message("CALL_CLOSED or CANCELLED\n"); - linphone_call_terminated(lc,ev); - break; - case EXOSIP_CALL_TIMEOUT: - case EXOSIP_CALL_NOANSWER: - ms_message("CALL_TIMEOUT or NOANSWER\n"); - linphone_call_failure(lc,ev); - break; - case EXOSIP_CALL_REQUESTFAILURE: - case EXOSIP_CALL_GLOBALFAILURE: - case EXOSIP_CALL_SERVERFAILURE: - ms_message("CALL_REQUESTFAILURE or GLOBALFAILURE or SERVERFAILURE\n"); - linphone_call_failure(lc,ev); - break; - case EXOSIP_CALL_INVITE: - ms_message("CALL_NEW\n"); - /* CALL_NEW is used twice in qos mode : - * when you receive invite (textinfo = "With QoS" or "Without QoS") - * and when you receive update (textinfo = "New Call") */ - linphone_inc_new_call(lc,ev); - break; - case EXOSIP_CALL_REINVITE: - linphone_handle_reinvite(lc,ev); - break; - case EXOSIP_CALL_ACK: - ms_message("CALL_ACK"); - linphone_handle_ack(lc,ev); - break; - case EXOSIP_CALL_REDIRECTED: - ms_message("CALL_REDIRECTED"); - linphone_call_redirected(lc,ev); - break; - case EXOSIP_CALL_PROCEEDING: - ms_message("CALL_PROCEEDING"); - linphone_call_proceeding(lc,ev); - break; - case EXOSIP_CALL_RINGING: - ms_message("CALL_RINGING"); - linphone_call_ringing(lc,ev); - break; - case EXOSIP_CALL_MESSAGE_NEW: - ms_message("EXOSIP_CALL_MESSAGE_NEW"); - linphone_call_message_new(lc,ev); - break; - case EXOSIP_CALL_MESSAGE_REQUESTFAILURE: - if (ev->did<0 && ev->response && - (ev->response->status_code==407 || ev->response->status_code==401)){ - eXosip_default_action(ev); - } - break; - case EXOSIP_IN_SUBSCRIPTION_NEW: - ms_message("CALL_SUBSCRIPTION_NEW or UPDATE"); - linphone_subscription_new(lc,ev); - break; - case EXOSIP_SUBSCRIPTION_UPDATE: - break; - case EXOSIP_SUBSCRIPTION_NOTIFY: - ms_message("CALL_SUBSCRIPTION_NOTIFY"); - linphone_notify_recv(lc,ev); - break; - case EXOSIP_SUBSCRIPTION_ANSWERED: - ms_message("EXOSIP_SUBSCRIPTION_ANSWERED, ev->sid=%i\n",ev->sid); - linphone_subscription_answered(lc,ev); - break; - case EXOSIP_SUBSCRIPTION_CLOSED: - ms_message("EXOSIP_SUBSCRIPTION_CLOSED\n"); - linphone_subscription_closed(lc,ev); - break; - case EXOSIP_CALL_RELEASED: - ms_message("CALL_RELEASED\n"); - linphone_call_released(lc, ev->cid); - break; - case EXOSIP_REGISTRATION_FAILURE: - ms_message("REGISTRATION_FAILURE\n"); - linphone_registration_faillure(lc,ev); - break; - case EXOSIP_REGISTRATION_SUCCESS: - linphone_authentication_ok(lc,ev); - linphone_registration_success(lc,ev); - break; - case EXOSIP_MESSAGE_NEW: - linphone_other_request(lc,ev); - break; - case EXOSIP_MESSAGE_REQUESTFAILURE: - if (ev->response && (ev->response->status_code == 407 || ev->response->status_code == 401)){ - /*the user is expected to have registered to the proxy, thus password is known*/ - eXosip_default_action(ev); - } - break; - default: - ms_message("Unhandled exosip event !"); - break; - } - eXosip_event_free(ev); -} diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 822dc169a..7aad0800f 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -313,7 +313,8 @@ void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call){ info=ortp_strdup_printf(ngettext("You have missed %i call.", "You have missed %i calls.", lc->missed_calls), lc->missed_calls); - lc->vtable.display_status(lc,info); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,info); ms_free(info); } else calllog->status=LinphoneCallAborted; @@ -1479,14 +1480,14 @@ void linphone_core_set_user_agent(const char *name, const char *ver){ * * @ingroup network_parameters **/ -void linphone_core_set_sip_port(LinphoneCore *lc,int port) +int linphone_core_set_sip_port(LinphoneCore *lc,int port) { const char *anyaddr; int err=0; - if (port==lc->sip_conf.sip_port) return; + if (port==lc->sip_conf.sip_port) return 0; lc->sip_conf.sip_port=port; - if (lc->sal==NULL) return; + if (lc->sal==NULL) return -1; if (lc->sip_conf.ipv6_enabled) anyaddr="::0"; @@ -1496,11 +1497,13 @@ void linphone_core_set_sip_port(LinphoneCore *lc,int port) if (err<0){ char *msg=ortp_strdup_printf("UDP port %i seems already in use ! Cannot initialize.",port); ms_warning(msg); - lc->vtable.display_warning(lc,msg); + if (lc->vtable.display_warning) + lc->vtable.display_warning(lc,msg); ms_free(msg); - return; + return -1; } apply_user_agent(lc); + return 0; } /** @@ -1541,7 +1544,8 @@ static void display_bandwidth(RtpSession *as, RtpSession *vs){ } static void linphone_core_disconnected(LinphoneCore *lc){ - lc->vtable.display_warning(lc,_("Remote end seems to have disconnected, the call is going to be closed.")); + if (lc->vtable.display_warning!=NULL) + lc->vtable.display_warning(lc,_("Remote end seems to have disconnected, the call is going to be closed.")); linphone_core_terminate_call(lc,NULL); } @@ -1754,9 +1758,11 @@ LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url) LinphoneAddress *uri; if (is_enum(url,&enum_domain)){ - lc->vtable.display_status(lc,_("Looking for telephone number destination...")); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,_("Looking for telephone number destination...")); if (enum_lookup(enum_domain,&enumres)<0){ - lc->vtable.display_status(lc,_("Could not resolve this number.")); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,_("Could not resolve this number.")); ms_free(enum_domain); return NULL; } @@ -1944,12 +1950,14 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro sal_call_set_local_media_description(call->op,call->localdesc); } barmsg=ortp_strdup_printf("%s %s", _("Contacting"), real_url); - lc->vtable.display_status(lc,barmsg); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,barmsg); ms_free(barmsg); if (err<0){ ms_warning("Could not initiate call."); - lc->vtable.display_status(lc,_("could not call")); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,_("could not call")); linphone_core_stop_media_streams(lc,call); linphone_call_destroy(call); lc->call=NULL; @@ -2410,7 +2418,8 @@ int linphone_core_accept_call(LinphoneCore *lc, const char *url) sal_op_set_contact(call->op,contact); sal_call_accept(call->op); - lc->vtable.display_status(lc,_("Connected.")); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,_("Connected.")); gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL); call->resultdesc=sal_call_get_final_media_description(call->op); if (call->resultdesc){ @@ -2444,7 +2453,8 @@ int linphone_core_terminate_call(LinphoneCore *lc, const char *url) lc->ringstream=NULL; } linphone_core_stop_media_streams(lc,call); - lc->vtable.display_status(lc,_("Call ended") ); + if (lc->vtable.display_status!=NULL) + lc->vtable.display_status(lc,_("Call ended") ); gstate_new_state(lc, GSTATE_CALL_END, NULL); linphone_call_destroy(call); return 0; diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 39606ae35..112f0ddaf 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -610,7 +610,7 @@ bool_t linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore *lc); int linphone_core_get_sip_port(LinphoneCore *lc); -void linphone_core_set_sip_port(LinphoneCore *lc,int port); +int linphone_core_set_sip_port(LinphoneCore *lc,int port); ortp_socket_t linphone_core_get_sip_socket(LinphoneCore *lc); diff --git a/coreapi/linphonecore_utils.h b/coreapi/linphonecore_utils.h index 43d6559bd..b4f3643bb 100644 --- a/coreapi/linphonecore_utils.h +++ b/coreapi/linphonecore_utils.h @@ -39,7 +39,7 @@ int lsd_player_stop(LsdPlayer *p); void lsd_player_enable_loop(LsdPlayer *p, bool_t loopmode); bool_t lsd_player_loop_enabled(const LsdPlayer *p); void lsd_player_set_gain(LsdPlayer *p, float gain); -LinphoneSoundDaemon lsd_player_get_daemon(const LsdPlayer *p); +LinphoneSoundDaemon *lsd_player_get_daemon(const LsdPlayer *p); LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname); LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd); diff --git a/coreapi/lsd.c b/coreapi/lsd.c index 2dd9898a5..9759ed961 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -62,6 +62,8 @@ struct _LinphoneSoundDaemon { static MSFilter *create_writer(MSSndCard *c){ LinphoneSoundDaemon *lsd=(LinphoneSoundDaemon*)c->data; + lsd->itcsink=ms_filter_new(MS_ITC_SINK_ID); + ms_filter_call_method(lsd->itcsink,MS_ITC_SINK_CONNECT,lsd->branches[0].player); return lsd->itcsink; } @@ -104,6 +106,10 @@ void linphone_sound_daemon_release_player(LinphoneSoundDaemon *obj, LsdPlayer * } } +LinphoneSoundDaemon *lsd_player_get_daemon(const LsdPlayer *p){ + return p->lsd; +} + int lsd_player_stop(LsdPlayer *p){ ms_filter_call_method_noarg(p->player,MS_PLAYER_PAUSE); return 0; @@ -245,8 +251,6 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname){ lsd->proxycard=ms_snd_card_new(&proxycard); lsd->proxycard->data=lsd; - - ms_filter_call_method(lsd->itcsink,MS_ITC_SINK_CONNECT,lsd->branches[0].player); return lsd; } diff --git a/coreapi/presence.c b/coreapi/presence.c index 8d9d39474..c56861d9d 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -130,7 +130,8 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, Sal tmp=linphone_address_as_string(friend); lf->status=estatus; lf->subscribe_active=TRUE; - lc->vtable.notify_presence_recv(lc,(LinphoneFriend*)lf); + if (lc->vtable.notify_presence_recv) + lc->vtable.notify_presence_recv(lc,(LinphoneFriend*)lf); ms_free(tmp); }else{ ms_message("But this person is not part of our friend list, so we don't care."); diff --git a/coreapi/test_lsd.c b/coreapi/test_lsd.c index 64b5d8a78..930980f83 100644 --- a/coreapi/test_lsd.c +++ b/coreapi/test_lsd.c @@ -30,7 +30,7 @@ static void play_finished(LsdPlayer *p){ const char *filename=(const char *)lsd_player_get_user_pointer (p); ms_message("Playing of %s is finished.",filename); if (!lsd_player_loop_enabled (p)){ - linphone_sound_daemon_release_player (lsd_player_get_daemon(p)); + linphone_sound_daemon_release_player (lsd_player_get_daemon(p),p); } }