Merge branch 'dev_multicall'

and improve documentation

Conflicts:
	coreapi/callbacks.c
	coreapi/linphonecore.c
	coreapi/linphonecore.h
This commit is contained in:
Simon Morlat 2010-08-26 16:01:10 +02:00
commit d4a57fff79
39 changed files with 2871 additions and 2598 deletions

View file

@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT([linphone],[3.3.2],[linphone-developers@nongnu.org])
AC_INIT([linphone],[3.3.99.1],[linphone-developers@nongnu.org])
AC_CANONICAL_SYSTEM
dnl Source packaging numbers
@ -15,7 +15,12 @@ LINPHONE_VERSION=$LINPHONE_MAJOR_VERSION.$LINPHONE_MINOR_VERSION.${LINPHONE_MICR
if test "$LINPHONE_EXTRA_VERSION" != "" ;then
LINPHONE_VERSION=$LINPHONE_VERSION.${LINPHONE_EXTRA_VERSION}
fi
LIBLINPHONE_SO_VERSION=`expr $LINPHONE_MINOR_VERSION + $LINPHONE_MAJOR_VERSION`:$LINPHONE_MICRO_VERSION:$LINPHONE_MINOR_VERSION
LIBLINPHONE_SO_CURRENT=4 dnl increment this number when you add/change/remove an interface
LIBLINPHONE_SO_REVISION=0 dnl increment this number when you change source code, without changing interfaces; set to 0 when incrementing CURRENT
LIBLINPHONE_SO_AGE=0 dnl increment this number when you add an interface, set to 0 if you remove an interface
LIBLINPHONE_SO_VERSION=$LIBLINPHONE_SO_CURRENT:$LIBLINPHONE_SO_REVISION:$LIBLINPHONE_SO_AGE
AC_SUBST(LIBLINPHONE_SO_VERSION, $LIBLINPHONE_SO_VERSION)
AC_SUBST(LINPHONE_VERSION)

View file

@ -56,13 +56,14 @@ extern char *lpc_strip_blanks(char *input);
static int lpc_cmd_help(LinphoneCore *, char *);
static int lpc_cmd_proxy(LinphoneCore *, char *);
static int lpc_cmd_call(LinphoneCore *, char *);
static int lpc_cmd_calls(LinphoneCore *, char *);
static int lpc_cmd_chat(LinphoneCore *, char *);
static int lpc_cmd_answer(LinphoneCore *, char *);
static int lpc_cmd_autoanswer(LinphoneCore *, char *);
static int lpc_cmd_terminate(LinphoneCore *, char *);
static int lpc_cmd_call_logs(LinphoneCore *, char *);
static int lpc_cmd_ipv6(LinphoneCore *, char *);
static int lpc_cmd_refer(LinphoneCore *, char *);
static int lpc_cmd_transfer(LinphoneCore *, char *);
static int lpc_cmd_quit(LinphoneCore *, char *);
static int lpc_cmd_nat(LinphoneCore *, char *);
static int lpc_cmd_stun(LinphoneCore *, char *);
@ -83,6 +84,8 @@ static int lpc_cmd_acodec(LinphoneCore *lc, char *args);
static int lpc_cmd_vcodec(LinphoneCore *lc, char *args);
static int lpc_cmd_codec(int type, LinphoneCore *lc, char *args);
static int lpc_cmd_echocancellation(LinphoneCore *lc, char *args);
static int lpc_cmd_pause(LinphoneCore *lc, char *args);
static int lpc_cmd_resume(LinphoneCore *lc, char *args);
static int lpc_cmd_mute_mic(LinphoneCore *lc, char *args);
static int lpc_cmd_unmute_mic(LinphoneCore *lc, char *args);
static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args);
@ -128,17 +131,24 @@ void linphonec_out(const char *fmt,...);
LPC_COMMAND commands[] = {
{ "help", lpc_cmd_help, "Print commands help", NULL },
{ "call", lpc_cmd_call, "Call a SIP uri",
"'call <sip-url>' "
": initiate a call to the specified destination."
"'call <sip-url>' \t: initiate a call to the specified destination.\n"
"'call show' \t: show all the current calls with their id and status.\n"
},
{ "calls", lpc_cmd_calls, "Show all the current calls with their id and status.\n",
NULL
},
{ "chat", lpc_cmd_chat, "Chat with a SIP uri",
"'chat <sip-url> \"message\"' "
": send a chat message \"message\" to the specified destination."
},
{ "terminate", lpc_cmd_terminate, "Terminate the current call",
NULL },
{ "terminate", lpc_cmd_terminate, "Terminate a call",
"'terminate' : Terminate the current call\n"
"'terminate <call id>' : Terminate the call with supplied id\n"
"'terminate <all>' : Terminate all the current calls\n"
},
{ "answer", lpc_cmd_answer, "Answer a call",
"Accept an incoming call."
"'answer' : Answer the current incoming call\n"
"'answer <call id>' : Answer the call with given id\n"
},
{ "autoanswer", lpc_cmd_autoanswer, "Show/set auto-answer mode",
"'autoanswer' \t: show current autoanswer mode\n"
@ -171,10 +181,10 @@ LPC_COMMAND commands[] = {
"'ipv6 enable' : enable the use of the ipv6 network.\n"
"'ipv6 disable' : do not use ipv6 network."
},
{ "refer", lpc_cmd_refer,
"Refer the current call to the specified destination.",
"'refer <sip-url>' or 'r <sip-url>' "
": refer the current call to the specified destination."
{ "transfer", lpc_cmd_transfer,
"Transfer a call to a specified destination.",
"'transfer <sip-uri>' : transfers the current active call to the destination sip-uri"
"'transfer <call id> <sip-uri>': transfers the call with 'id' to the destination sip-uri"
},
{ "nat", lpc_cmd_nat, "Set nat address",
"'nat' : show nat settings.\n"
@ -231,19 +241,24 @@ LPC_COMMAND commands[] = {
"'vcodec list' : list video codecs\n"
"'vcodec enable <index>' : enable available video codec\n"
"'vcodec disable <index>' : disable video codec" },
{ "ec", lpc_cmd_echocancellation, "Echo cancellation",
"'ec on [<delay>] [<tail>] [<framesize>]' : turn EC on with given delay, tail length and framesize\n"
"'ec off' : turn echo cancellation (EC) off\n"
"'ec show' : show EC status" },
{ "ec", lpc_cmd_echocancellation, "Echo cancellation",
"'ec on [<delay>] [<tail>] [<framesize>]' : turn EC on with given delay, tail length and framesize\n"
"'ec off' : turn echo cancellation (EC) off\n"
"'ec show' : show EC status" },
{ "pause", lpc_cmd_pause, "pause a call",
"'pause' : pause the current call\n"},
{ "resume", lpc_cmd_resume, "resume a call",
"'resume' : resume the unique call\n"
"'resume <call id>' : hold off the call with given id\n"},
{ "mute", lpc_cmd_mute_mic,
"Mute microphone and suspend voice transmission."},
{ "unmute", lpc_cmd_unmute_mic,
"Unmute microphone and resume voice transmission."},
"Unmute microphone and resume voice transmission."},
{ "nortp-on-audio-mute", lpc_cmd_rtp_no_xmit_on_audio_mute,
"Set the rtp_no_xmit_on_audio_mute configuration parameter",
" If set to 1 then rtp transmission will be muted when\n"
" audio is muted , otherwise rtp is always sent."},
{ (char *)NULL, (lpc_cmd_handler)NULL, (char *)NULL, (char *)NULL }
"Set the rtp_no_xmit_on_audio_mute configuration parameter",
" If set to 1 then rtp transmission will be muted when\n"
" audio is muted , otherwise rtp is always sent."},
{ (char *)NULL, (lpc_cmd_handler)NULL, (char *)NULL, (char *)NULL }
};
/***************************************************************************
@ -388,6 +403,35 @@ lpc_cmd_help(LinphoneCore *lc, char *arg)
static char callee_name[256]={0};
static char caller_name[256]={0};
static const char *get_call_status(LinphoneCall *call){
switch(linphone_call_get_state(call)){
case LinphoneCallPaused:
if (linphone_call_get_refer_to (call)!=NULL){
return "Paused (transfered)";
}else{
return "Paused";
}
break;
case LinphoneCallIncomingReceived:
return "Pending";
break;
case LinphoneCallOutgoingInit:
case LinphoneCallOutgoingProgress:
return "Dialing out";
break;
case LinphoneCallOutgoingEarlyMedia:
case LinphoneCallOutgoingRinging:
return "Remote ringing";
break;
default:
if (linphone_call_has_transfer_pending(call)){
return "Running (transfer pending)";
}else
return "Running";
}
return "";
}
static int
lpc_cmd_call(LinphoneCore *lc, char *args)
{
@ -395,14 +439,14 @@ lpc_cmd_call(LinphoneCore *lc, char *args)
{
return 0;
}
if ( lc->call != NULL )
{
linphonec_out("Terminate current call first.\n");
}
else
{
if ( -1 == linphone_core_invite(lc, args) )
LinphoneCall *call;
if ( linphone_core_in_call(lc) )
{
linphonec_out("Terminate or hold on the current call first.\n");
return 1;
}
if ( NULL == (call=linphone_core_invite(lc, args)) )
{
linphonec_out("Error from linphone_core_invite.\n");
}
@ -414,6 +458,32 @@ lpc_cmd_call(LinphoneCore *lc, char *args)
return 1;
}
static int
lpc_cmd_calls(LinphoneCore *lc, char *args){
const MSList *calls = linphone_core_get_calls(lc);
if(calls)
{
const MSList *p_calls = calls;
linphonec_out("ID\t\tDestination\t\t\t\tStatus\n---------------------------------------------------------------------\n");
while(p_calls != NULL)
{
LinphoneCall *call=(LinphoneCall*)p_calls->data;
char *tmp=linphone_call_get_remote_address_as_string(call);
linphonec_out("%li\t%s\t\t\t%s\r\n",
(long)linphone_call_get_user_pointer (call),
tmp,
get_call_status(call));
p_calls = p_calls->next;
ms_free(tmp);
}
}else
{
linphonec_out("No active call.\n");
}
return 1;
}
static int
lpc_cmd_chat(LinphoneCore *lc, char *args)
{
@ -456,12 +526,34 @@ void linphonec_set_caller(const char *caller){
}
static int
lpc_cmd_refer(LinphoneCore *lc, char *args)
lpc_cmd_transfer(LinphoneCore *lc, char *args)
{
if (args)
linphone_core_refer(lc, args);
else{
linphonec_out("refer needs an argument\n");
if (args){
LinphoneCall *call;
const char *refer_to=NULL;
char arg1[256]={0};
char arg2[266]={0};
int n=sscanf(args,"%s %s",arg1,arg2);
if (n==1 || isalpha(*arg1)){
call=linphone_core_get_current_call(lc);
if (call==NULL && linphone_core_get_calls_nb (lc)==1){
call=(LinphoneCall*)linphone_core_get_calls(lc)->data;
}
refer_to=args;
if (call==NULL){
linphonec_out("No active call, please specify a call id among the ones listed by 'calls' command.\n");
return 0;
}
}else{
long id=atoi(arg1);
refer_to=args+strlen(arg1)+1;
call=linphonec_get_call(id);
if (call==NULL) return 0;
}
linphone_core_transfer_call(lc, call, refer_to);
}else{
linphonec_out("Transfer command requires at least one argument\n");
return 0;
}
return 1;
}
@ -469,21 +561,66 @@ lpc_cmd_refer(LinphoneCore *lc, char *args)
static int
lpc_cmd_terminate(LinphoneCore *lc, char *args)
{
if ( -1 == linphone_core_terminate_call(lc, NULL) )
{
linphonec_out("No active call.\n");
if (linphone_core_get_calls(lc)==NULL){
linphonec_out("No active calls");
return 1;
}
return 1;
if (!args)
{
if ( -1 == linphone_core_terminate_call(lc, NULL) ){
linphonec_out("Could not stop the active call.\n");
}
return 1;
}
if(strcmp(args,"all")==0){
linphonec_out("We are going to stop all the calls.\n");
linphone_core_terminate_all_calls(lc);
return 1;
}else{
/*the argument is a linphonec call id */
long id=atoi(args);
LinphoneCall *call=linphonec_get_call(id);
if (call){
if (linphone_core_terminate_call(lc,call)==-1){
linphonec_out("Could not stop the call with id %li",id);
}
}else return 0;
return 1;
}
return 0;
}
static int
lpc_cmd_answer(LinphoneCore *lc, char *args)
{
if ( -1 == linphone_core_accept_call(lc, NULL) )
lpc_cmd_answer(LinphoneCore *lc, char *args){
if (!args)
{
linphonec_out("No incoming call.\n");
int nb=ms_list_size(linphone_core_get_calls(lc));
if (nb==1){
//if just one call is present answer the only one in passing NULL to the linphone_core_accept_call ...
if ( -1 == linphone_core_accept_call(lc, NULL) )
{
linphonec_out("Fail to accept incoming call\n");
}
}else if (nb==0){
linphonec_out("There are no calls to answer.\n");
}else{
linphonec_out("Multiple calls in progress, please specify call id.\n");
return 0;
}
return 1;
}else{
long id;
if (sscanf(args,"%li",&id)==1){
LinphoneCall *call=linphonec_get_call (id);
if (linphone_core_accept_call (lc,call)==-1){
linphonec_out("Fail to accept call %i\n",id);
}
}else return 0;
return 1;
}
return 1;
return 0;
}
static int
@ -531,7 +668,7 @@ lpc_cmd_nat(LinphoneCore *lc, char *args)
}
nat = linphone_core_get_nat_address(lc);
use = linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_NAT_ADDRESS;
use = linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress;
linphonec_out("Nat address: %s%s\n", nat ? nat : "unspecified" , use ? "" : " (disabled - use 'firewall nat' to enable)");
return 1;
@ -552,7 +689,7 @@ lpc_cmd_stun(LinphoneCore *lc, char *args)
}
stun = linphone_core_get_stun_server(lc);
use = linphone_core_get_firewall_policy(lc)==LINPHONE_POLICY_USE_STUN;
use = linphone_core_get_firewall_policy(lc)==LinphonePolicyUseStun;
linphonec_out("Stun server: %s%s\n", stun ? stun : "unspecified" , use? "" : " (disabled - use 'firewall stun' to enable)");
return 1;
@ -569,7 +706,7 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args)
{
if (strcmp(args,"none")==0)
{
linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_NO_FIREWALL);
linphone_core_set_firewall_policy(lc,LinphonePolicyNoFirewall);
}
else if (strcmp(args,"stun")==0)
{
@ -579,7 +716,7 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args)
linphonec_out("No stun server address is defined, use 'stun <address>' first\n");
return 1;
}
linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_STUN);
linphone_core_set_firewall_policy(lc,LinphonePolicyUseStun);
}
else if (strcmp(args,"nat")==0)
{
@ -589,19 +726,19 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args)
linphonec_out("No nat address is defined, use 'nat <address>' first");
return 1;
}
linphone_core_set_firewall_policy(lc,LINPHONE_POLICY_USE_NAT_ADDRESS);
linphone_core_set_firewall_policy(lc,LinphonePolicyUseNatAddress);
}
}
switch(linphone_core_get_firewall_policy(lc))
{
case LINPHONE_POLICY_NO_FIREWALL:
case LinphonePolicyNoFirewall:
linphonec_out("No firewall\n");
break;
case LINPHONE_POLICY_USE_STUN:
case LinphonePolicyUseStun:
linphonec_out("Using stun server %s to discover firewall address\n", setting ? setting : linphone_core_get_stun_server(lc));
break;
case LINPHONE_POLICY_USE_NAT_ADDRESS:
case LinphonePolicyUseNatAddress:
linphonec_out("Using supplied nat address %s.\n", setting ? setting : linphone_core_get_nat_address(lc));
break;
}
@ -1084,7 +1221,59 @@ lpc_cmd_staticpic(LinphoneCore *lc, char *args)
return 0; /* Syntax error */
}
static int lpc_cmd_pause(LinphoneCore *lc, char *args){
if(linphone_core_in_call(lc))
{
linphone_core_pause_call(lc,linphone_core_get_current_call(lc));
return 1;
}
linphonec_out("you can only pause when a call is in process\n");
return 0;
}
static int lpc_cmd_resume(LinphoneCore *lc, char *args){
if(linphone_core_in_call(lc))
{
linphonec_out("There is already a call in process pause or stop it first");
return 1;
}
if (args)
{
long id;
int n = sscanf(args, "%li", &id);
if (n == 1){
LinphoneCall *call=linphonec_get_call (id);
if (call){
if(linphone_core_resume_call(lc,call)==-1){
linphonec_out("There was a problem to resume the call check the remote address you gave %s\n",args);
}
}
return 1;
}else return 0;
}
else
{
const MSList *calls = linphone_core_get_calls(lc);
int nbcalls=ms_list_size(calls);
if( nbcalls == 1)
{
if(linphone_core_resume_call(lc,calls->data) < 0)
{
linphonec_out("There was a problem to resume the unique call.\n");
}
return 1;
}else if (nbcalls==0){
linphonec_out("There is no calls at this time.\n");
return 1;
}else{
linphonec_out("There are %i calls at this time, please specify call id as given with 'calls' command.\n");
}
}
return 0;
}
/***************************************************************************
*
@ -1612,31 +1801,31 @@ static int lpc_cmd_status(LinphoneCore *lc, char *args)
}
else if (strstr(args,"hook"))
{
gstate_t call_state=linphone_core_get_state(lc,GSTATE_GROUP_CALL);
/*
if (!cfg || !linphone_proxy_config_is_registered(cfg)){
linphonec_out("unregistered\n");
return 1;
}
*/
LinphoneCall *call=linphone_core_get_current_call (lc);
LinphoneCallState call_state=LinphoneCallIdle;
if (call) call_state=linphone_call_get_state(call);
switch(call_state){
case GSTATE_CALL_OUT_INVITE:
case LinphoneCallOutgoingInit:
case LinphoneCallOutgoingProgress:
linphonec_out("hook=dialing\n");
break;
case GSTATE_CALL_IDLE:
case LinphoneCallIdle:
linphonec_out("hook=offhook\n");
break;
case GSTATE_CALL_OUT_CONNECTED:
linphonec_out("Call out, hook=%s duration=%i, muted=%s rtp-xmit-muted=%s\n", linphonec_get_callee(),
case LinphoneCallStreamsRunning:
case LinphoneCallConnected:
if (linphone_call_get_dir(call)==LinphoneCallOutgoing){
linphonec_out("Call out, hook=%s duration=%i, muted=%s rtp-xmit-muted=%s\n", linphonec_get_callee(),
linphone_core_get_current_call_duration(lc),
lc->audio_muted ? "yes" : "no",
linphone_core_is_mic_muted (lc) ? "yes" : "no",
linphone_core_is_rtp_muted(lc) ? "yes" : "no");
break;
case GSTATE_CALL_IN_CONNECTED:
linphonec_out("hook=answered duration=%i\n" ,
linphone_core_get_current_call_duration(lc));
}else{
linphonec_out("hook=answered duration=%i\n" ,
linphone_core_get_current_call_duration(lc));
}
break;
case GSTATE_CALL_IN_INVITE:
case LinphoneCallIncomingReceived:
linphonec_out("Incoming call from %s\n",linphonec_get_caller());
break;
default:
@ -1874,36 +2063,32 @@ static int lpc_cmd_echocancellation(LinphoneCore *lc, char *args){
static int lpc_cmd_mute_mic(LinphoneCore *lc, char *args)
{
if ( lc->call != NULL )
linphone_core_mute_mic(lc, 1);
return 1;
linphone_core_mute_mic(lc, 1);
return 1;
}
static int lpc_cmd_unmute_mic(LinphoneCore *lc, char *args)
{
if ( lc->call != NULL )
linphone_core_mute_mic(lc, 0);
return 1;
static int lpc_cmd_unmute_mic(LinphoneCore *lc, char *args){
linphone_core_mute_mic(lc, 0);
return 1;
}
static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args)
{
bool_t rtp_xmit_off=FALSE;
char *status;
gstate_t call_state=linphone_core_get_state(lc,GSTATE_GROUP_CALL);
bool_t rtp_xmit_off=FALSE;
char *status;
if(args){
if(strstr(args,"1"))rtp_xmit_off=TRUE;
if(call_state == GSTATE_CALL_IDLE)
linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_xmit_off);
else
linphonec_out("nortp-on-audio-mute: call in progress - cannot change state\n");
}
rtp_xmit_off=linphone_core_get_rtp_no_xmit_on_audio_mute(lc);
if(rtp_xmit_off)status="off";
else status="on";
linphonec_out("rtp transmit %s when audio muted\n",status);
return 1;
if(args){
if(strstr(args,"1"))rtp_xmit_off=TRUE;
if(linphone_core_get_current_call (lc)==NULL)
linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_xmit_off);
else
linphonec_out("nortp-on-audio-mute: call in progress - cannot change state\n");
}
rtp_xmit_off=linphone_core_get_rtp_no_xmit_on_audio_mute(lc);
if (rtp_xmit_off) status="off";
else status="on";
linphonec_out("rtp transmit %s when audio muted\n",status);
return 1;
}

View file

@ -112,25 +112,24 @@ static char **linephonec_readline_completion(const char *text,
#endif
/* These are callback for linphone core */
static void linphonec_call_received(LinphoneCore *lc, const char *from);
static void linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm,
const char *username);
static void linphonec_display_refer (LinphoneCore * lc,const char *refer_to);
static void linphonec_display_refer (LinphoneCore * lc, const char *refer_to);
static void linphonec_display_something (LinphoneCore * lc, const char *something);
static void linphonec_display_url (LinphoneCore * lc, const char *something, const char *url);
static void linphonec_display_warning (LinphoneCore * lc, const char *something);
static void stub () {}
static void linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg);
static void linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event);
static void linphonec_notify_presence_received(LinphoneCore *lc,LinphoneFriend *fid);
static void linphonec_new_unknown_subscriber(LinphoneCore *lc,
LinphoneFriend *lf, const char *url);
static void linphonec_bye_received(LinphoneCore *lc, const char *from);
static void linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr,
const char *from, const char *msg);
static void linphonec_display_status (LinphoneCore * lc, const char *something);
static void linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate);
static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf);
static void linphonec_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf);
static void print_prompt(LinphoneCore *opm);
void linphonec_out(const char *fmt,...);
/***************************************************************************
*
* Global variables
@ -170,34 +169,23 @@ static ortp_pipe_t server_sock;
#endif /*_WIN32_WCE*/
LinphoneCoreVTable linphonec_vtable
#if !defined (_MSC_VER)
= {
.show =(ShowInterfaceCb) stub,
.inv_recv = linphonec_call_received,
.bye_recv = linphonec_bye_received,
.notify_recv = linphonec_notify_received,
.notify_presence_recv = linphonec_notify_presence_received,
.new_unknown_subscriber = linphonec_new_unknown_subscriber,
.auth_info_requested = linphonec_prompt_for_auth,
.display_status = linphonec_display_status,
.display_message=linphonec_display_something,
#ifdef VINCENT_MAURY_RSVP
/* the yes/no dialog box */
.display_yes_no= (DisplayMessageCb) stub,
#endif
.display_warning=linphonec_display_warning,
.display_url=linphonec_display_url,
.display_question=(DisplayQuestionCb)stub,
.text_received=linphonec_text_received,
.general_state=linphonec_general_state,
.dtmf_received=linphonec_dtmf_received,
.refer_received=linphonec_display_refer
void linphonec_call_identify(LinphoneCall* call){
static long callid=1;
linphone_call_set_user_pointer (call,(void*)callid);
callid++;
}
#endif /*_WIN32_WCE*/
;
LinphoneCall *linphonec_get_call(long id){
const MSList *elem=linphone_core_get_calls(linphonec);
for (;elem!=NULL;elem=elem->next){
LinphoneCall *call=(LinphoneCall*)elem->data;
if (linphone_call_get_user_pointer (call)==(void*)id){
return call;
}
}
linphonec_out("Sorry, no call with id %i exists at this time.",id);
return NULL;
}
/***************************************************************************
*
@ -209,10 +197,9 @@ LinphoneCoreVTable linphonec_vtable
* Linphone core callback
*/
static void
linphonec_display_refer (LinphoneCore * lc,const char *refer_to)
linphonec_display_refer (LinphoneCore * lc, const char *refer_to)
{
fprintf (stdout, "The distant end point asked to transfer the call to %s,don't forget to terminate the call if not\n%s", refer_to,prompt);
fflush(stdout);
linphonec_out("Receiving out of call refer to %s", refer_to);
}
/*
@ -254,19 +241,6 @@ linphonec_display_url (LinphoneCore * lc, const char *something, const char *url
fprintf (stdout, "%s : %s\n", something, url);
}
/*
* Linphone core callback
*/
static void
linphonec_call_received(LinphoneCore *lc, const char *from)
{
linphonec_set_caller(from);
if ( auto_answer) {
answer_call=TRUE;
}
}
/*
* Linphone core callback
*/
@ -296,16 +270,16 @@ linphonec_prompt_for_auth(LinphoneCore *lc, const char *realm, const char *usern
* Linphone core callback
*/
static void
linphonec_notify_received(LinphoneCore *lc,const char *from,const char *msg)
linphonec_notify_received(LinphoneCore *lc, LinphoneCall *call, const char *from,const char *event)
{
printf("Notify type %s from %s\n", msg, from);
if(!strcmp(msg,"refer"))
if(!strcmp(event,"refer"))
{
printf("The distant SIP end point get the refer we can close the call\n");
linphonec_parse_command_line(linphonec, "terminate");
linphonec_out("The distand endpoint %s of call %li has been transfered, you can safely close the call.\n",
from,(long)linphone_call_get_user_pointer (call));
}
}
/*
* Linphone core callback
*/
@ -332,17 +306,41 @@ linphonec_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf,
}
/*
* Linphone core callback
*/
static void
linphonec_bye_received(LinphoneCore *lc, const char *from)
{
// Should change prompt back to original maybe
// printing this is unneeded as we'd get a "Communication ended"
// message trough display_status callback anyway
//printf("Bye received from %s\n", from);
static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState st, const char *msg){
char *from=linphone_call_get_remote_address_as_string(call);
long id=(long)linphone_call_get_user_pointer (call);
switch(st){
case LinphoneCallEnd:
linphonec_out("Call %i with %s ended.\n", id, from);
break;
case LinphoneCallResuming:
linphonec_out("Resuming call %i with %s.\n", id, from);
break;
case LinphoneCallStreamsRunning:
linphonec_out("Media streams established with %s for call %i.\n", from,id);
break;
case LinphoneCallPausing:
linphonec_out("Pausing call %i with %s.\n", id, from);
break;
case LinphoneCallPaused:
linphonec_out("Call %i with %s is now paused.\n", id, from);
break;
case LinphoneCallIncomingReceived:
linphonec_call_identify(call);
id=(long)linphone_call_get_user_pointer (call);
linphonec_set_caller(from);
if ( auto_answer) {
answer_call=TRUE;
}
linphonec_out("Receiving new incoming call from %s, assigned id %i", from,id);
break;
case LinphoneCallOutgoingInit:
linphonec_call_identify(call);
break;
default:
break;
}
ms_free(from);
}
/*
@ -357,64 +355,11 @@ linphonec_text_received(LinphoneCore *lc, LinphoneChatRoom *cr,
}
static void linphonec_dtmf_received(LinphoneCore *lc, int dtmf){
fprintf(stdout,"Receiving tone %c\n",dtmf);
static void linphonec_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf){
char *from=linphone_call_get_remote_address_as_string(call);
fprintf(stdout,"Receiving tone %c from %s\n",dtmf,from);
fflush(stdout);
}
static void
linphonec_general_state (LinphoneCore * lc, LinphoneGeneralState *gstate)
{
if (show_general_state) {
switch(gstate->new_state) {
case GSTATE_POWER_OFF:
printf("GSTATE_POWER_OFF");
break;
case GSTATE_POWER_STARTUP:
printf("GSTATE_POWER_STARTUP");
break;
case GSTATE_POWER_ON:
printf("GSTATE_POWER_ON");
break;
case GSTATE_POWER_SHUTDOWN:
printf("GSTATE_POWER_SHUTDOWN");
break;
case GSTATE_REG_NONE:
printf("GSTATE_REG_NONE");
break;
case GSTATE_REG_OK:
printf("GSTATE_REG_OK");
break;
case GSTATE_REG_FAILED:
printf("GSTATE_REG_FAILED");
break;
case GSTATE_CALL_IDLE:
printf("GSTATE_CALL_IDLE");
break;
case GSTATE_CALL_OUT_INVITE:
printf("GSTATE_CALL_OUT_INVITE");
break;
case GSTATE_CALL_OUT_CONNECTED:
printf("GSTATE_CALL_OUT_CONNECTED");
break;
case GSTATE_CALL_IN_INVITE:
printf("GSTATE_CALL_IN_INVITE");
break;
case GSTATE_CALL_IN_CONNECTED:
printf("GSTATE_CALL_IN_CONNECTED");
break;
case GSTATE_CALL_END:
printf("GSTATE_CALL_END");
break;
case GSTATE_CALL_ERROR:
printf("GSTATE_CALL_ERROR");
break;
default:
printf("GSTATE_UNKNOWN_%d",gstate->new_state);
}
if (gstate->message) printf(" %s", gstate->message);
printf("\n");
}
ms_free(from);
}
static char received_prompt[PROMPT_MAX_LEN];
@ -596,6 +541,8 @@ bool_t linphonec_get_autoanswer(){
return auto_answer;
}
LinphoneCoreVTable linphonec_vtable={0};
/***************************************************************************/
/*
* Main
@ -621,31 +568,24 @@ char **convert_args_to_ascii(int argc, _TCHAR **wargv){
int _tmain(int argc, _TCHAR* wargv[]) {
char **argv=convert_args_to_ascii(argc,wargv);
trace_level=6;
linphonec_vtable.show =(ShowInterfaceCb) stub;
linphonec_vtable.inv_recv = linphonec_call_received;
linphonec_vtable.bye_recv = linphonec_bye_received;
linphonec_vtable.notify_presence_recv = linphonec_notify_received;
linphonec_vtable.new_unknown_subscriber = linphonec_new_unknown_subscriber;
linphonec_vtable.auth_info_requested = linphonec_prompt_for_auth;
linphonec_vtable.display_status = linphonec_display_status;
linphonec_vtable.display_message=linphonec_display_something;
#ifdef VINCENT_MAURY_RSVP
/* the yes/no dialog box */
linphonec_vtable.display_yes_no= (DisplayMessageCb) stub;
#endif
linphonec_vtable.display_warning=linphonec_display_warning;
linphonec_vtable.display_url=linphonec_display_url;
linphonec_vtable.display_question=(DisplayQuestionCb)stub;
linphonec_vtable.text_received=linphonec_text_received;
linphonec_vtable.general_state=linphonec_general_state;
linphonec_vtable.dtmf_received=linphonec_dtmf_received;
#else
int
main (int argc, char *argv[]) {
#endif
linphonec_vtable.call_state_changed=linphonec_call_state_changed;
linphonec_vtable.notify_presence_recv = linphonec_notify_presence_received;
linphonec_vtable.new_unknown_subscriber = linphonec_new_unknown_subscriber;
linphonec_vtable.auth_info_requested = linphonec_prompt_for_auth;
linphonec_vtable.display_status = linphonec_display_status;
linphonec_vtable.display_message=linphonec_display_something;
linphonec_vtable.display_warning=linphonec_display_warning;
linphonec_vtable.display_url=linphonec_display_url;
linphonec_vtable.text_received=linphonec_text_received;
linphonec_vtable.dtmf_received=linphonec_dtmf_received;
linphonec_vtable.refer_received=linphonec_display_refer;
linphonec_vtable.notify_recv=linphonec_notify_received;
if (! linphonec_init(argc, argv) ) exit(EXIT_FAILURE);
linphonec_main_loop (linphonec, sipAddr);
@ -766,11 +706,10 @@ void linphonec_main_loop_exit(void){
void
linphonec_finish(int exit_status)
{
printf("Terminating...\n");
linphonec_out("Terminating...\n");
/* Terminate any pending call */
linphonec_parse_command_line(linphonec, "terminate");
linphonec_command_finished();
linphone_core_terminate_all_calls(linphonec);
#ifdef HAVE_READLINE
linphonec_finish_readline();
#endif

View file

@ -112,6 +112,8 @@ void linphonec_set_autoanswer(bool_t enabled);
bool_t linphonec_get_autoanswer();
void linphonec_command_finished(void);
void linphonec_set_caller(const char *caller);
LinphoneCall *linphonec_get_call(long id);
void linphonec_call_identify(LinphoneCall* call);
#endif /* def LINPHONEC_H */

View file

@ -6,7 +6,7 @@ EXTRA_DIST=linphonecore_jni.cc
## Process this file with automake to produce Makefile.in
linphone_includedir=$(includedir)/linphone
linphone_include_HEADERS=linphonecore.h ../config.h lpconfig.h sipsetup.h
linphone_include_HEADERS=linphonecore.h linphonecore_utils.h ../config.h lpconfig.h sipsetup.h
INCLUDES = \
-I$(top_srcdir)\
@ -32,9 +32,10 @@ liblinphone_la_SOURCES=\
authentication.c \
lpconfig.c lpconfig.h \
chat.c \
general_state.c \
linphonecall.c \
sipsetup.c sipsetup.h \
siplogin.c
siplogin.c \
lsd.c linphonecore_utils.h
liblinphone_la_LDFLAGS= -version-info $(LIBLINPHONE_SO_VERSION) -no-undefined
@ -48,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) \

View file

@ -26,16 +26,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
static void linphone_connect_incoming(LinphoneCore *lc, LinphoneCall *call){
if (lc->vtable.show)
lc->vtable.show(lc);
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Connected."));
call->state=LCStateAVRunning;
if (lc->ringstream!=NULL){
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
linphone_core_start_media_streams(lc,call);
linphone_call_start_media_streams(call);
}
static void call_received(SalOp *h){
@ -47,26 +42,22 @@ static void call_received(SalOp *h){
LinphoneAddress *from_parsed;
/* 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);
if (lc->presence_mode==LINPHONE_STATUS_BUSY)
if (lc->presence_mode==LinphoneStatusBusy ||
lc->presence_mode==LinphoneStatusOffline ||
lc->presence_mode==LinphoneStatusDoNotDisturb ||
lc->presence_mode==LinphoneStatusMoved){
if (lc->presence_mode==LinphoneStatusBusy )
sal_call_decline(h,SalReasonBusy,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)
else if (lc->presence_mode==LinphoneStatusOffline)
sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
else if (lc->presence_mode==LINPHONE_STATUS_NOT_DISTURB)
else if (lc->presence_mode==LinphoneStatusDoNotDisturb)
sal_call_decline(h,SalReasonTemporarilyUnavailable,NULL);
else if (lc->alt_contact!=NULL && lc->presence_mode==LINPHONE_STATUS_MOVED)
else if (lc->alt_contact!=NULL && lc->presence_mode==LinphoneStatusMoved)
sal_call_decline(h,SalReasonRedirect,lc->alt_contact);
else
sal_call_decline(h,SalReasonBusy,NULL);
sal_op_release(h);
return;
}
if (lc->call!=NULL){/*busy*/
if (!linphone_core_can_we_add_call(lc)){/*busy*/
sal_call_decline(h,SalReasonBusy,NULL);
sal_op_release(h);
return;
@ -75,56 +66,72 @@ static void call_received(SalOp *h){
to=sal_op_get_to(h);
call=linphone_call_new_incoming(lc,linphone_address_new(from),linphone_address_new(to),h);
lc->call=call;
sal_call_set_local_media_description(h,call->localdesc);
call->resultdesc=sal_call_get_final_media_description(h);
if (call->resultdesc)
sal_media_description_ref(call->resultdesc);
if (call->resultdesc && sal_media_description_empty(call->resultdesc)){
sal_call_decline(h,SalReasonMedia,NULL);
linphone_call_destroy(call);
lc->call=NULL;
linphone_call_unref(call);
return;
}
/* the call is acceptable so we can now add it to our list */
if(linphone_core_add_call(lc,call)!= 0)
{
ms_warning("we cannot handle anymore call\n");
sal_call_decline(h,SalReasonMedia,NULL);
linphone_call_unref(call);
return;
}
from_parsed=linphone_address_new(sal_op_get_from(h));
linphone_address_clean(from_parsed);
tmp=linphone_address_as_string(from_parsed);
linphone_address_destroy(from_parsed);
gstate_new_state(lc, GSTATE_CALL_IN_INVITE, tmp);
linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call");
barmesg=ortp_strdup_printf("%s %s%s",tmp,_("is contacting you"),
(sal_call_autoanswer_asked(h)) ?_(" and asked autoanswer."):_("."));
if (lc->vtable.show) lc->vtable.show(lc);
if (lc->vtable.display_status)
lc->vtable.display_status(lc,barmesg);
/* play the ring */
if (lc->sound_conf.ring_sndcard!=NULL){
/* play the ring if this is the only call*/
if (lc->sound_conf.ring_sndcard!=NULL && ms_list_size(lc->calls)==1){
if (lc->ringstream && lc->dmfs_playing_start_time!=0){
ring_stop(lc->ringstream);
lc->ringstream=NULL;
lc->dmfs_playing_start_time=0;
}
ms_message("Starting local ring...");
lc->ringstream=ring_start(lc->sound_conf.local_ring,2000,lc->sound_conf.ring_sndcard);
if(lc->ringstream==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,ringcard);
}
else
{
ms_message("the local ring is already started");
}
}else{
/*TODO : play a tone within the context of the current call */
}
linphone_call_set_state(call,LCStateRinging);
sal_call_notify_ringing(h);
#if !(__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000)
linphone_core_init_media_streams(lc,lc->call);
linphone_call_init_media_streams(call);
#endif
if (lc->vtable.inv_recv) lc->vtable.inv_recv(lc,tmp);
ms_free(barmesg);
ms_free(tmp);
}
static void call_ringing(SalOp *h){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h));
LinphoneCall *call=lc->call;
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h);
SalMediaDescription *md;
if (call==NULL) return;
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Remote ringing."));
md=sal_call_get_final_media_description(h);
if (md==NULL){
if (lc->ringstream && lc->dmfs_playing_start_time!=0){
@ -134,13 +141,14 @@ static void call_ringing(SalOp *h){
}
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);
gstate_new_state(lc, GSTATE_CALL_OUT_RINGING, NULL);
lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard);
linphone_call_set_state(call,LinphoneCallOutgoingRinging,"Remote ringing");
}
}else{
/*accept early media */
if (lc->audiostream && lc->audiostream->ticker!=NULL){
if (call->audiostream && call->audiostream->ticker!=NULL){
/*streams already started */
ms_message("Early media already started.");
return;
@ -150,36 +158,34 @@ static void call_ringing(SalOp *h){
if (lc->vtable.show) lc->vtable.show(lc);
if (lc->vtable.display_status)
lc->vtable.display_status(lc,_("Early media."));
gstate_new_state(lc, GSTATE_CALL_OUT_RINGING, NULL);
linphone_call_set_state(call,LinphoneCallOutgoingEarlyMedia,"Early media");
if (lc->ringstream!=NULL){
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
ms_message("Doing early media...");
linphone_core_start_media_streams(lc,call);
linphone_call_start_media_streams(call);
call->media_pending=TRUE;
}
call->state=LCStateRinging;
}
/*
* could be reach :
* - when the call is accepted
* - when a request is accepted (pause, resume)
*/
static void call_accepted(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=lc->call;
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call==NULL){
ms_warning("No call to accept.");
return ;
}
if (sal_op_get_user_pointer(op)!=lc->call){
ms_warning("call_accepted: ignoring.");
return;
}
if (call->state==LCStateAVRunning){
return ; /*already accepted*/
}
if (lc->audiostream->ticker!=NULL){
/*case where we accepted early media */
linphone_core_stop_media_streams(lc,call);
linphone_core_init_media_streams(lc,call);
if ((call->audiostream!=NULL) && (call->audiostream->ticker!=NULL)){
/*case where we accepted early media or already in call*/
linphone_call_stop_media_streams(call);
linphone_call_init_media_streams(call);
}
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
@ -188,32 +194,55 @@ static void call_accepted(SalOp *op){
sal_media_description_ref(call->resultdesc);
call->media_pending=FALSE;
}
if (call->state==LinphoneCallOutgoingProgress ||
call->state==LinphoneCallOutgoingRinging ||
call->state==LinphoneCallOutgoingEarlyMedia){
linphone_call_set_state(call,LinphoneCallConnected,"Connected");
}
if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
gstate_new_state(lc, GSTATE_CALL_OUT_CONNECTED, NULL);
linphone_connect_incoming(lc,call);
if (sal_media_description_has_dir(call->resultdesc,SalStreamSendOnly)){
/*we initiated a pause*/
if (lc->vtable.display_status){
char *tmp=linphone_call_get_remote_address_as_string (call);
char *msg=ms_strdup_printf(_("Call with %s is paused."),tmp);
lc->vtable.display_status(lc,msg);
ms_free(tmp);
ms_free(msg);
}
linphone_call_set_state(call,LinphoneCallPaused,"Call paused");
}else if (sal_media_description_has_dir(call->resultdesc,SalStreamRecvOnly)){
/*we are put on hold when the call is initially accepted */
if (lc->vtable.display_status){
char *tmp=linphone_call_get_remote_address_as_string (call);
char *msg=ms_strdup_printf(_("Call answered by %s - on hold."),tmp);
lc->vtable.display_status(lc,msg);
ms_free(tmp);
ms_free(msg);
}
linphone_call_set_state(call,LinphoneCallPaused,"Call paused");
}else{
linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)");
}
linphone_connect_incoming (lc,call);
}else{
/*send a bye*/
ms_error("Incompatible SDP offer received in 200Ok, need to abort the call");
linphone_core_terminate_call(lc,NULL);
linphone_core_abort_call(lc,call,"No codec intersection");
}
}
static void call_ack(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=lc->call;
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call==NULL){
ms_warning("No call to be ACK'd");
return ;
}
if (sal_op_get_user_pointer(op)!=lc->call){
ms_warning("call_ack: ignoring.");
return;
}
if (call->media_pending){
if (lc->audiostream->ticker!=NULL){
if (call->audiostream->ticker!=NULL){
/*case where we accepted early media */
linphone_core_stop_media_streams(lc,call);
linphone_core_init_media_streams(lc,call);
linphone_call_stop_media_streams(call);
linphone_call_init_media_streams(call);
}
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
@ -221,62 +250,86 @@ static void call_ack(SalOp *op){
if (call->resultdesc)
sal_media_description_ref(call->resultdesc);
if (call->resultdesc && !sal_media_description_empty(call->resultdesc)){
gstate_new_state(lc, GSTATE_CALL_IN_CONNECTED, NULL);
linphone_connect_incoming(lc,call);
linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
}else{
/*send a bye*/
ms_error("Incompatible SDP response received in ACK, need to abort the call");
linphone_core_terminate_call(lc,NULL);
linphone_core_abort_call(lc,call,"No codec intersection");
return;
}
call->media_pending=FALSE;
}
}
static void call_updated(SalOp *op){
/* this callback is called when an incoming re-INVITE modifies the session*/
static void call_updating(SalOp *op){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
linphone_core_stop_media_streams(lc,call);
linphone_core_init_media_streams(lc,call);
if (call->resultdesc)
sal_media_description_unref(call->resultdesc);
call->resultdesc=sal_call_get_final_media_description(op);
if (call->resultdesc){
if (call->resultdesc)
sal_media_description_ref(call->resultdesc);
if (!sal_media_description_empty(call->resultdesc)){
linphone_connect_incoming(lc,call);
if (call->resultdesc && !sal_media_description_empty(call->resultdesc))
{
if (call->state==LinphoneCallPaused &&
sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv) && strcmp(call->resultdesc->addr,"0.0.0.0")!=0){
/*make sure we can be resumed */
if (lc->current_call!=NULL && lc->current_call!=call){
ms_warning("Attempt to be resumed but already in call with somebody else!");
/*we are actively running another call, reject with a busy*/
sal_call_decline (op,SalReasonBusy,NULL);
return;
}
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We have been resumed..."));
linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
}
else if(call->state==LinphoneCallStreamsRunning &&
sal_media_description_has_dir(call->resultdesc,SalStreamRecvOnly) && !strcmp(call->resultdesc->addr,"0.0.0.0")){
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We are being paused..."));
linphone_call_set_state (call,LinphoneCallPaused,"Call paused");
if (lc->current_call!=call){
ms_error("Inconsitency detected: current call is %p but call %p is being paused !",lc->current_call,call);
}
lc->current_call=NULL;
}
/*accept the modification (sends a 200Ok)*/
sal_call_accept(op);
linphone_call_stop_media_streams (call);
linphone_call_init_media_streams (call);
linphone_call_start_media_streams (call);
}
if (lc->current_call==NULL) linphone_core_start_pending_refered_calls (lc);
}
static void call_terminated(SalOp *op, const char *from){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
if (sal_op_get_user_pointer(op)!=lc->call){
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (linphone_call_get_state(call)==LinphoneCallEnd || linphone_call_get_state(call)==LinphoneCallError){
ms_warning("call_terminated: ignoring.");
return;
}
ms_message("Current call terminated...");
if (lc->ringstream!=NULL) {
//we stop the call only if we have this current call or if we are in call
if (lc->ringstream!=NULL && ( (ms_list_size(lc->calls) == 1) || linphone_core_in_call(lc) )) {
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
linphone_core_stop_media_streams(lc,lc->call);
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){
LinphoneAddress *addr=linphone_address_new(from);
char *tmp;
linphone_address_clean(addr);
tmp=linphone_address_as_string(addr);
lc->vtable.bye_recv(lc,tmp);
ms_free(tmp);
linphone_address_destroy(addr);
}
linphone_call_destroy(lc->call);
lc->call=NULL;
linphone_call_stop_media_streams(call);
if (lc->vtable.show!=NULL)
lc->vtable.show(lc);
if (lc->vtable.display_status!=NULL)
lc->vtable.display_status(lc,_("Call terminated."));
linphone_call_set_state(call, LinphoneCallEnd,"Call ended");
}
static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details){
static void call_failure(SalOp *op, SalError error, SalReason sr, const char *details, int code){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
char *msg486=_("User is busy.");
char *msg480=_("User is temporarily unavailable.");
@ -284,12 +337,13 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
char *msg600=_("User does not want to be disturbed.");
char *msg603=_("Call declined.");
const char *msg=details;
LinphoneCall *call=lc->call;
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (sal_op_get_user_pointer(op)!=lc->call){
ms_warning("call_failure: ignoring.");
return;
if (call==NULL){
ms_warning("Call faillure reported on already cleaned call ?");
return ;
}
if (lc->vtable.show) lc->vtable.show(lc);
if (error==SalErrorNoResponse){
@ -342,17 +396,15 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
lc->vtable.display_status(lc,_("Call failed."));
}
}
if (lc->ringstream!=NULL) {
ring_stop(lc->ringstream);
lc->ringstream=NULL;
}
linphone_core_stop_media_streams(lc,call);
if (call!=NULL) {
linphone_call_destroy(call);
if (sr!=SalReasonDeclined) gstate_new_state(lc, GSTATE_CALL_ERROR, msg);
else gstate_new_state(lc, GSTATE_CALL_END, msg);
lc->call=NULL;
}
linphone_call_stop_media_streams (call);
if (sr!=SalReasonDeclined) linphone_call_set_state(call,LinphoneCallError,msg);
else linphone_call_set_state(call,LinphoneCallEnd,"Call declined.");
}
static void auth_requested(SalOp *h, const char *realm, const char *username){
@ -387,42 +439,77 @@ static void register_success(SalOp *op, bool_t registered){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
char *msg;
cfg->registered=registered;
gstate_new_state(lc, GSTATE_REG_OK, NULL);
if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
if (lc->vtable.display_status)
linphone_proxy_config_set_state(cfg, registered ? LinphoneRegistrationOk : LinphoneRegistrationCleared ,
registered ? "Registration sucessful" : "Unregistration done");
if (lc->vtable.display_status){
if (cfg->registered) msg=ms_strdup_printf(_("Registration on %s successful."),sal_op_get_proxy(op));
else msg=ms_strdup_printf(_("Unregistration on %s done."),sal_op_get_proxy(op));
lc->vtable.display_status(lc,msg);
ms_free(msg);
ms_free(msg);
}
}
static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),(details!=NULL) ? details : _("no response timeout"));
if (lc->vtable.display_status) lc->vtable.display_status(lc,msg);
gstate_new_state(lc, GSTATE_REG_FAILED, msg);
ms_free(msg);
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)sal_op_get_user_pointer(op);
if (cfg==NULL){
ms_warning("Registration failed for unknown proxy config.");
return ;
}
if (details==NULL)
details=_("no response timeout");
if (lc->vtable.display_status) {
char *msg=ortp_strdup_printf(_("Registration on %s failed: %s"),sal_op_get_proxy(op),details );
lc->vtable.display_status(lc,msg);
ms_free(msg);
}
linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,details);
}
static void vfu_request(SalOp *op){
#ifdef VIDEO_ENABLED
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
if (lc->videostream)
video_stream_send_vfu(lc->videostream);
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op);
if (call==NULL){
ms_warning("VFU request but no call !");
return ;
}
if (call->videostream)
video_stream_send_vfu(call->videostream);
#endif
}
static void dtmf_received(SalOp *op, char dtmf){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (lc->vtable.dtmf_received != NULL)
lc->vtable.dtmf_received(lc, dtmf);
lc->vtable.dtmf_received(lc, call, dtmf);
}
static void refer_received(Sal *sal, SalOp *op, const char *referto){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
if (lc->vtable.refer_received){
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
if (call){
if (call->refer_to!=NULL){
ms_free(call->refer_to);
}
call->refer_to=ms_strdup(referto);
call->refer_pending=TRUE;
linphone_call_set_state(call,LinphoneCallRefered,"Refered");
if (lc->vtable.display_status){
char *msg=ms_strdup_printf(_("We are transferred to %s"),referto);
lc->vtable.display_status(lc,msg);
ms_free(msg);
}
if (lc->current_call==NULL) linphone_core_start_pending_refered_calls (lc);
sal_refer_accept(op);
}else if (lc->vtable.refer_received){
lc->vtable.refer_received(lc,referto);
if (op) sal_refer_accept(op);
sal_refer_accept(op);
}
}
@ -433,10 +520,10 @@ static void text_received(Sal *sal, const char *from, const char *msg){
static void notify(SalOp *op, const char *from, const char *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op);
ms_message("get a %s notify from %s",msg,from);
if(lc->vtable.notify_recv)
lc->vtable.notify_recv(lc,from,msg);
lc->vtable.notify_recv(lc,call,from,msg);
}
static void notify_presence(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
@ -464,10 +551,14 @@ static void ping_reply(SalOp *op){
LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
ms_message("ping reply !");
if (call){
if (call->state==LCStatePreEstablishing){
if (call->state==LinphoneCallOutgoingInit){
linphone_core_start_invite(call->core,call,NULL);
}
}
else
{
ms_warning("ping reply without call attached...");
}
}
SalCallbacks linphone_sal_callbacks={
@ -475,7 +566,7 @@ SalCallbacks linphone_sal_callbacks={
call_ringing,
call_accepted,
call_ack,
call_updated,
call_updating,
call_terminated,
call_failure,
auth_requested,

View file

@ -55,7 +55,7 @@ void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg){
if(linphone_core_is_in_communication_with(cr->lc,cr->peer))
{
ms_message("send SIP message into the call\n");
op = cr->lc->call->op;
op = (linphone_core_get_current_call(cr->lc))->op;
}
else
{

File diff suppressed because it is too large Load diff

View file

@ -29,37 +29,37 @@
const char *linphone_online_status_to_string(LinphoneOnlineStatus ss){
const char *str=NULL;
switch(ss){
case LINPHONE_STATUS_ONLINE:
case LinphoneStatusOnline:
str=_("Online");
break;
case LINPHONE_STATUS_BUSY:
case LinphoneStatusBusy:
str=_("Busy");
break;
case LINPHONE_STATUS_BERIGHTBACK:
case LinphoneStatusBeRightBack:
str=_("Be right back");
break;
case LINPHONE_STATUS_AWAY:
case LinphoneStatusAway:
str=_("Away");
break;
case LINPHONE_STATUS_ONTHEPHONE:
case LinphoneStatusOnThePhone:
str=_("On the phone");
break;
case LINPHONE_STATUS_OUTTOLUNCH:
case LinphoneStatusOutToLunch:
str=_("Out to lunch");
break;
case LINPHONE_STATUS_NOT_DISTURB:
case LinphoneStatusDoNotDisturb:
str=_("Do not disturb");
break;
case LINPHONE_STATUS_MOVED:
case LinphoneStatusMoved:
str=_("Moved");
break;
case LINPHONE_STATUS_ALT_SERVICE:
case LinphoneStatusAltService:
str=_("Using another messaging service");
break;
case LINPHONE_STATUS_OFFLINE:
case LinphoneStatusOffline:
str=_("Offline");
break;
case LINPHONE_STATUS_PENDING:
case LinphoneStatusPending:
str=_("Pending");
break;
default:
@ -138,7 +138,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){
}else from=linphone_core_get_primary_contact(fr->lc);
if (fr->outsub==NULL){
/* people for which we don't have yet an answer should appear as offline */
fr->status=LINPHONE_STATUS_OFFLINE;
fr->status=LinphoneStatusOffline;
/*
if (fr->lc->vtable.notify_recv)
fr->lc->vtable.notify_recv(fr->lc,(LinphoneFriend*)fr);
@ -157,7 +157,7 @@ void __linphone_friend_do_subscribe(LinphoneFriend *fr){
LinphoneFriend * linphone_friend_new(){
LinphoneFriend *obj=ms_new0(LinphoneFriend,1);
obj->pol=LinphoneSPAccept;
obj->status=LINPHONE_STATUS_OFFLINE;
obj->status=LinphoneStatusOffline;
obj->subscribe=TRUE;
return obj;
}
@ -243,37 +243,37 @@ int linphone_friend_set_inc_subscribe_policy(LinphoneFriend *fr, LinphoneSubscri
SalPresenceStatus linphone_online_status_to_sal(LinphoneOnlineStatus os){
switch(os){
case LINPHONE_STATUS_OFFLINE:
case LinphoneStatusOffline:
return SalPresenceOffline;
break;
case LINPHONE_STATUS_ONLINE:
case LinphoneStatusOnline:
return SalPresenceOnline;
break;
case LINPHONE_STATUS_BUSY:
case LinphoneStatusBusy:
return SalPresenceBusy;
break;
case LINPHONE_STATUS_BERIGHTBACK:
case LinphoneStatusBeRightBack:
return SalPresenceBerightback;
break;
case LINPHONE_STATUS_AWAY:
case LinphoneStatusAway:
return SalPresenceAway;
break;
case LINPHONE_STATUS_ONTHEPHONE:
case LinphoneStatusOnThePhone:
return SalPresenceOnthephone;
break;
case LINPHONE_STATUS_OUTTOLUNCH:
case LinphoneStatusOutToLunch:
return SalPresenceOuttolunch;
break;
case LINPHONE_STATUS_NOT_DISTURB:
case LinphoneStatusDoNotDisturb:
return SalPresenceDonotdisturb;
break;
case LINPHONE_STATUS_MOVED:
case LinphoneStatusMoved:
return SalPresenceMoved;
break;
case LINPHONE_STATUS_ALT_SERVICE:
case LinphoneStatusAltService:
return SalPresenceAltService;
break;
case LINPHONE_STATUS_PENDING:
case LinphoneStatusPending:
return SalPresenceOffline;
break;
default:
@ -347,7 +347,7 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){
if (fr->inc_subscribe_pending){
switch(fr->pol){
case LinphoneSPWait:
linphone_friend_notify(fr,LINPHONE_STATUS_PENDING);
linphone_friend_notify(fr,LinphoneStatusPending);
break;
case LinphoneSPAccept:
if (fr->lc!=NULL)
@ -356,7 +356,7 @@ void linphone_friend_apply(LinphoneFriend *fr, LinphoneCore *lc){
}
break;
case LinphoneSPDeny:
linphone_friend_notify(fr,LINPHONE_STATUS_OFFLINE);
linphone_friend_notify(fr,LinphoneStatusOffline);
break;
}
fr->inc_subscribe_pending=FALSE;

View file

@ -83,35 +83,36 @@ static void linphone_core_set_state(LinphoneCore *lc, gstate_group_t group, gsta
void gstate_new_state(struct _LinphoneCore *lc,
gstate_t new_state,
LinphoneGeneralStateContext gctx,
const char *message) {
LinphoneGeneralState states_arg;
/* determine the affected group */
if (new_state < GSTATE_REG_NONE)
states_arg.group = GSTATE_GROUP_POWER;
else if (new_state < GSTATE_CALL_IDLE)
states_arg.group = GSTATE_GROUP_REG;
else
states_arg.group = GSTATE_GROUP_CALL;
/* store the new state while remembering the old one */
states_arg.new_state = new_state;
states_arg.old_state = linphone_core_get_state(lc,states_arg.group);
linphone_core_set_state(lc, states_arg.group,new_state);
states_arg.message = message;
/*printf("gstate_new_state: %s\t-> %s\t(%s)\n",
_gstates_text[states_arg.old_state],
_gstates_text[states_arg.new_state],
message);*/
LinphoneGeneralState states_arg;
/* call the virtual method */
if (lc->vtable.general_state)
lc->vtable.general_state(lc, &states_arg);
/* immediately proceed to idle state */
if (new_state == GSTATE_CALL_END ||
new_state == GSTATE_CALL_ERROR)
gstate_new_state(lc, GSTATE_CALL_IDLE, NULL);
/* determine the affected group */
if (new_state < GSTATE_REG_NONE)
states_arg.group = GSTATE_GROUP_POWER;
else if (new_state < GSTATE_CALL_IDLE)
states_arg.group = GSTATE_GROUP_REG;
else
states_arg.group = GSTATE_GROUP_CALL;
/* store the new state while remembering the old one */
states_arg.new_state = new_state;
states_arg.old_state = linphone_core_get_state(lc,states_arg.group);
linphone_core_set_state(lc, states_arg.group,new_state);
states_arg.message = message;
/*printf("gstate_new_state: %s\t-> %s\t(%s)\n",
_gstates_text[states_arg.old_state],
_gstates_text[states_arg.new_state],
message);*/
/* call the virtual method */
if (lc->vtable.general_state)
lc->vtable.general_state(lc, &states_arg, gctx);
/* immediately proceed to idle state */
if (new_state == GSTATE_CALL_END ||
new_state == GSTATE_CALL_ERROR)
gstate_new_state(lc, GSTATE_CALL_IDLE, gctx, NULL);
}

View file

@ -89,7 +89,7 @@ RECURSIVE = NO
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH = ../
EXAMPLE_PATH = ../../ .
EXAMPLE_PATTERNS =
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =

View file

@ -31,3 +31,22 @@ endif
clean-local:
rm -rf doc
noinst_PROGRAMS=helloworld
helloworld_SOURCES=helloworld.c
helloworld_LDADD=$(top_builddir)/coreapi/liblinphone.la
INCLUDES=-I$(top_srcdir)/coreapi
AM_CFLAGS=$(STRICT_OPTIONS) -DIN_LINPHONE \
$(ORTP_CFLAGS) \
$(OSIP_CFLAGS) \
$(EXOSIP_CFLAGS) \
-DENABLE_TRACE \
-DLOG_DOMAIN=\"LinphoneCore\" \
$(IPV6_CFLAGS) \
-DORTP_INET6 \
$(VIDEO_CFLAGS)

View file

@ -29,64 +29,11 @@
*/
/**
* @defgroup tutorial_liblinphone Tutorial: Placing and receiving calls with liblinphone
*
<H1>Initialize liblinphone</H1>
The first thing to do is to initialize the library passing it a set of callbacks functions to receive
various notifications: incoming calls, progress of calls etc...
These callbacks are all grouped in the LinphoneCoreVTable structure.
All are optionnals (use NULL if you don't need them).
The following code shows how initialize liblinphone:
<PRE>
##include <linphonecore.h>
//callback function for notification of incoming calls
static void on_invite_recv(LinphoneCore *lc, const char *from){
printf("Receiving a call from %s\n",from);
}
//callback function for notification end of calls (by remote)
static void on_bye_recv(LinphoneCore *lc, const char *from){
printf("Remote end hangup\n");
}
/
static void on_display_status(LinphoneCore *lc, const char *msg){
printf("%s",msg);
}
int main(int argc, char *argv[]){
LinphoneCoreVTable vtable;
memset(&vtable,0,sizeof(vtable));
vtable.inv_recv=&on_invite_recv;
vtable.bye_recv=&on_bye_recv;
vtable.display_status=&on_display_status;
}
</PRE>
/**
* @defgroup initializing Initialization and destruction
*
* @defgroup initializing Initializing liblinphone
**/
/**
* @defgroup call_control Call control
*
* The application can initiate outgoing calls with linphone_core_invite().
* It is notified of incoming call thanks to the inv_recv callback of the LinphoneCoreVTable
* structure that is passed at creation of the LinphoneCore object.
* It can then answer calls with linphone_core_accept_call().
* Calls can be terminated or declined with linphone_core_terminate_call().
* The application is notified when the remote party hangups thanks to
* bye_recv callback of the #LinphoneCoreVTable.
* @defgroup call_control Placing and receiving calls
**/
/**
@ -109,6 +56,7 @@ The following code shows how initialize liblinphone:
* @defgroup call_logs Managing call logs
**/
/**
* @defgroup linphone_address SIP address parser API.
* This api is useful for manipulating SIP addresses ('from' or 'to' headers).
@ -117,3 +65,14 @@ The following code shows how initialize liblinphone:
/**
* @defgroup misc Miscenalleous: logs, version strings, config storage
**/
/**
* @defgroup tutorial_liblinphone Tutorial: Placing calls with liblinphone
*
* The minimalist program below illustrates how to initialize liblinphone and place and outgoing call.
* @include helloworld.c
*
**/

723
coreapi/linphonecall.c Normal file
View file

@ -0,0 +1,723 @@
/*
linphone
Copyright (C) 2010 Belledonne Communications SARL
(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.
*/
#ifdef WIN32
#include <time.h>
#endif
#include "linphonecore.h"
#include "sipsetup.h"
#include "lpconfig.h"
#include "private.h"
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/msvolume.h"
#include "mediastreamer2/msequalizer.h"
static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, bool_t only_one_codec){
MSList *l=NULL;
const MSList *it;
for(it=codecs;it!=NULL;it=it->next){
PayloadType *pt=(PayloadType*)it->data;
if ((pt->flags & PAYLOAD_TYPE_ENABLED) && linphone_core_check_payload_type_usability(lc,pt)){
l=ms_list_append(l,payload_type_clone(pt));
if (only_one_codec) break;
}
}
return l;
}
static SalMediaDescription *create_local_media_description(LinphoneCore *lc,
LinphoneCall *call, const char *username, bool_t only_one_codec){
MSList *l;
PayloadType *pt;
SalMediaDescription *md=sal_media_description_new();
md->nstreams=1;
strncpy(md->addr,call->localip,sizeof(md->addr));
strncpy(md->username,username,sizeof(md->username));
md->bandwidth=linphone_core_get_download_bandwidth(lc);
/*set audio capabilities */
strncpy(md->streams[0].addr,call->localip,sizeof(md->streams[0].addr));
md->streams[0].port=call->audio_port;
md->streams[0].proto=SalProtoRtpAvp;
md->streams[0].type=SalAudio;
md->streams[0].ptime=lc->net_conf.down_ptime;
l=make_codec_list(lc,lc->codecs_conf.audio_codecs,only_one_codec);
pt=payload_type_clone(rtp_profile_get_payload_from_mime(&av_profile,"telephone-event"));
l=ms_list_append(l,pt);
md->streams[0].payloads=l;
if (lc->dw_audio_bw>0)
md->streams[0].bandwidth=lc->dw_audio_bw;
if (linphone_core_video_enabled (lc)){
md->nstreams++;
md->streams[1].port=call->video_port;
md->streams[1].proto=SalProtoRtpAvp;
md->streams[1].type=SalVideo;
l=make_codec_list(lc,lc->codecs_conf.video_codecs,only_one_codec);
md->streams[1].payloads=l;
if (lc->dw_video_bw)
md->streams[1].bandwidth=lc->dw_video_bw;
}
return md;
}
static int find_port_offset(LinphoneCore *lc){
int offset;
MSList *elem;
int audio_port;
bool_t already_used=FALSE;
for(offset=0;offset<100;offset+=2){
audio_port=linphone_core_get_audio_port (lc)+offset;
already_used=FALSE;
for(elem=lc->calls;elem!=NULL;elem=elem->next){
LinphoneCall *call=(LinphoneCall*)elem->data;
if (call->audio_port==audio_port) {
already_used=TRUE;
break;
}
}
if (!already_used) break;
}
if (offset==100){
ms_error("Could not find any free port !");
return -1;
}
return offset;
}
static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
int port_offset;
call->refcnt=1;
call->state=LinphoneCallIdle;
call->start_time=time(NULL);
call->media_start_time=0;
call->log=linphone_call_log_new(call, from, to);
linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
port_offset=find_port_offset (call->core);
if (port_offset==-1) return;
call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
call->video_port=linphone_core_get_video_port(call->core)+port_offset;
}
static void discover_mtu(LinphoneCore *lc, const char *remote){
int mtu;
if (lc->net_conf.mtu==0 ){
/*attempt to discover mtu*/
mtu=ms_discover_mtu(remote);
if (mtu>0){
ms_set_mtu(mtu);
ms_message("Discovered mtu is %i, RTP payload max size is %i",
mtu, ms_get_payload_max_size());
}
}
}
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to)
{
LinphoneCall *call=ms_new0(LinphoneCall,1);
call->dir=LinphoneCallOutgoing;
call->op=sal_op_new(lc->sal);
sal_op_set_user_pointer(call->op,call);
call->core=lc;
linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
linphone_call_init_common(call,from,to);
call->localdesc=create_local_media_description (lc,call,
linphone_address_get_username(from),FALSE);
if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun)
linphone_core_run_stun_tests(call->core,call);
discover_mtu(lc,linphone_address_get_domain (to));
return call;
}
LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
LinphoneCall *call=ms_new0(LinphoneCall,1);
LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
char *to_str;
char *from_str;
call->dir=LinphoneCallIncoming;
sal_op_set_user_pointer(op,call);
call->op=op;
call->core=lc;
if (lc->sip_conf.ping_with_options){
/*the following sends an option request back to the caller so that
we get a chance to discover our nat'd address before answering.*/
call->ping_op=sal_op_new(lc->sal);
to_str=linphone_address_as_string(to);
from_str=linphone_address_as_string(from);
sal_op_set_route(call->ping_op,sal_op_get_network_origin(call->op));
sal_op_set_user_pointer(call->ping_op,call);
sal_ping(call->ping_op,to_str,from_str);
ms_free(to_str);
ms_free(from_str);
}
linphone_address_clean(from);
linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
linphone_call_init_common(call, from, to);
call->localdesc=create_local_media_description (lc,call,
linphone_address_get_username(me),lc->sip_conf.only_one_codec);
if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseStun)
linphone_core_run_stun_tests(call->core,call);
discover_mtu(lc,linphone_address_get_domain(from));
linphone_address_destroy(me);
return call;
}
/* this function is called internally to get rid of a call.
It performs the following tasks:
- remove the call from the internal list of calls
- unref the LinphoneCall object
- update the call logs accordingly
*/
static void linphone_call_set_terminated(LinphoneCall *call){
LinphoneCallStatus status=LinphoneCallAborted;
LinphoneCore *lc=call->core;
linphone_core_update_allocated_audio_bandwidth(lc);
if (call->state==LinphoneCallEnd){
status=LinphoneCallSuccess;
}
linphone_call_log_completed(call->log,call, status);
if (call == lc->current_call){
ms_message("Resetting the current call");
lc->current_call=NULL;
linphone_core_start_pending_refered_calls(lc);
}
if (linphone_core_del_call(lc,call) != 0){
ms_error("Could not remove the call from the list !!!");
}
if (ms_list_size(lc->calls)==0)
linphone_core_notify_all_friends(lc,lc->presence_mode);
if (call->op!=NULL) {
/* so that we cannot have anymore upcalls for SAL
concerning this call*/
sal_op_release(call->op);
call->op=NULL;
}
linphone_call_unref(call);
}
void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message){
LinphoneCore *lc=call->core;
if (call->state!=cstate){
if (cstate!=LinphoneCallRefered){
/*LinphoneCallRefered is rather an event, not a state.
Indeed it does not change the state of the call (still paused or running)*/
call->state=cstate;
}
if (lc->vtable.call_state_changed)
lc->vtable.call_state_changed(lc,call,cstate,message);
}
if (call->state==LinphoneCallEnd || call->state==LinphoneCallError)
linphone_call_set_terminated (call);
}
static void linphone_call_destroy(LinphoneCall *obj)
{
if (obj->op!=NULL) {
sal_op_release(obj->op);
obj->op=NULL;
}
if (obj->resultdesc!=NULL) {
sal_media_description_unref(obj->resultdesc);
obj->resultdesc=NULL;
}
if (obj->localdesc!=NULL) {
sal_media_description_unref(obj->localdesc);
obj->localdesc=NULL;
}
if (obj->ping_op) {
sal_op_release(obj->ping_op);
}
if (obj->refer_to){
ms_free(obj->refer_to);
}
ms_free(obj);
}
/**
* @addtogroup call_control
* @{
**/
/**
* Increments the call 's reference count.
* An application that wishes to retain a pointer to call object
* must use this function to unsure the pointer remains
* valid. Once the application no more needs this pointer,
* it must call linphone_call_unref().
**/
void linphone_call_ref(LinphoneCall *obj){
obj->refcnt++;
}
/**
* Decrements the call object reference count.
* See linphone_call_ref().
**/
void linphone_call_unref(LinphoneCall *obj){
obj->refcnt--;
if (obj->refcnt==0)
linphone_call_destroy(obj);
}
/**
* Returns the remote address associated to this call
*
**/
const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call){
return call->dir==LinphoneCallIncoming ? call->log->from : call->log->to;
}
/**
* Returns the remote address associated to this call as a string.
*
* The result string must be freed by user using ms_free().
**/
char *linphone_call_get_remote_address_as_string(const LinphoneCall *call){
return linphone_address_as_string(linphone_call_get_remote_address(call));
}
/**
* Retrieves the call's current state.
**/
LinphoneCallState linphone_call_get_state(const LinphoneCall *call){
return call->state;
}
/**
* Get the user_pointer in the LinphoneCall
*
* @ingroup call_control
*
* return user_pointer an opaque user pointer that can be retrieved at any time
**/
void *linphone_call_get_user_pointer(LinphoneCall *call)
{
return call->user_pointer;
}
/**
* Set the user_pointer in the LinphoneCall
*
* @ingroup call_control
*
* the user_pointer is an opaque user pointer that can be retrieved at any time in the LinphoneCall
**/
void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer)
{
call->user_pointer = user_pointer;
}
/**
* Returns the call log associated to this call.
**/
LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call){
return call->log;
}
/**
* Returns the refer-to uri (if the call was transfered).
**/
const char *linphone_call_get_refer_to(const LinphoneCall *call){
return call->refer_to;
}
LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call){
return call->log->dir;
}
/**
* Returns true if this calls has received a transfer that has not been
* executed yet.
* Pending transfers are executed when this call is being paused or closed,
* locally or by remote endpoint.
* If the call is already paused while receiving the transfer request, the
* transfer immediately occurs.
**/
bool_t linphone_call_has_transfer_pending(const LinphoneCall *call){
return call->refer_pending;
}
/**
* @}
**/
#ifdef TEST_EXT_RENDERER
static void rendercb(void *data, const MSPicture *local, const MSPicture *remote){
ms_message("rendercb, local buffer=%p, remote buffer=%p",
local ? local->planes[0] : NULL, remote? remote->planes[0] : NULL);
}
#endif
void linphone_call_init_media_streams(LinphoneCall *call){
LinphoneCore *lc=call->core;
SalMediaDescription *md=call->localdesc;
AudioStream *audiostream;
call->audiostream=audiostream=audio_stream_new(md->streams[0].port,linphone_core_ipv6_enabled(lc));
if (linphone_core_echo_limiter_enabled(lc)){
const char *type=lp_config_get_string(lc->config,"sound","el_type","mic");
if (strcasecmp(type,"mic")==0)
audio_stream_enable_echo_limiter(audiostream,ELControlMic);
else if (strcasecmp(type,"full")==0)
audio_stream_enable_echo_limiter(audiostream,ELControlFull);
}
audio_stream_enable_gain_control(audiostream,TRUE);
if (linphone_core_echo_cancellation_enabled(lc)){
int len,delay,framesize;
len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
delay=lp_config_get_int(lc->config,"sound","ec_delay",0);
framesize=lp_config_get_int(lc->config,"sound","ec_framesize",0);
audio_stream_set_echo_canceller_params(audiostream,len,delay,framesize);
}
audio_stream_enable_automatic_gain_control(audiostream,linphone_core_agc_enabled(lc));
{
int enabled=lp_config_get_int(lc->config,"sound","noisegate",0);
audio_stream_enable_noise_gate(audiostream,enabled);
}
if (lc->a_rtp)
rtp_session_set_transports(audiostream->session,lc->a_rtp,lc->a_rtcp);
#ifdef VIDEO_ENABLED
if ((lc->video_conf.display || lc->video_conf.capture) && md->streams[1].port>0){
call->videostream=video_stream_new(md->streams[1].port,linphone_core_ipv6_enabled(lc));
#ifdef TEST_EXT_RENDERER
video_stream_set_render_callback(call->videostream,rendercb,NULL);
#endif
}
#else
call->videostream=NULL;
#endif
}
static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
static void linphone_core_dtmf_received(RtpSession* s, int dtmf, void* user_data){
LinphoneCore* lc = (LinphoneCore*)user_data;
if (dtmf<0 || dtmf>15){
ms_warning("Bad dtmf value %i",dtmf);
return;
}
if (lc->vtable.dtmf_received != NULL)
lc->vtable.dtmf_received(lc, linphone_core_get_current_call(lc), dtmf_tab[dtmf]);
}
static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){
if (st->equalizer){
MSFilter *f=st->equalizer;
int enabled=lp_config_get_int(lc->config,"sound","eq_active",0);
const char *gains=lp_config_get_string(lc->config,"sound","eq_gains",NULL);
ms_filter_call_method(f,MS_EQUALIZER_SET_ACTIVE,&enabled);
if (enabled){
if (gains){
do{
int bytes;
MSEqualizerGain g;
if (sscanf(gains,"%f:%f:%f %n",&g.frequency,&g.gain,&g.width,&bytes)==3){
ms_message("Read equalizer gains: %f(~%f) --> %f",g.frequency,g.width,g.gain);
ms_filter_call_method(f,MS_EQUALIZER_SET_GAIN,&g);
gains+=bytes;
}else break;
}while(1);
}
}
}
}
static void post_configure_audio_streams(LinphoneCall*call){
AudioStream *st=call->audiostream;
LinphoneCore *lc=call->core;
float mic_gain=lp_config_get_float(lc->config,"sound","mic_gain",1);
float thres = 0;
float recv_gain;
float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05);
float ng_floorgain=lp_config_get_float(lc->config,"sound","ng_floorgain",0);
int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0);
if (mic_gain!=-1)
audio_stream_set_mic_gain(st,mic_gain);
call->audio_muted=FALSE;
recv_gain = lc->sound_conf.soft_play_lev;
if (recv_gain != 0) {
linphone_core_set_playback_gain_db (lc,recv_gain);
}
if (st->volsend){
ms_filter_call_method(st->volsend,MS_VOLUME_REMOVE_DC,&dc_removal);
}
if (linphone_core_echo_limiter_enabled(lc)){
float speed=lp_config_get_float(lc->config,"sound","el_speed",-1);
thres=lp_config_get_float(lc->config,"sound","el_thres",-1);
float force=lp_config_get_float(lc->config,"sound","el_force",-1);
int sustain=lp_config_get_int(lc->config,"sound","el_sustain",-1);
MSFilter *f=NULL;
if (st->el_type!=ELInactive){
f=st->volsend;
if (speed==-1) speed=0.03;
if (force==-1) force=25;
ms_filter_call_method(f,MS_VOLUME_SET_EA_SPEED,&speed);
ms_filter_call_method(f,MS_VOLUME_SET_EA_FORCE,&force);
if (thres!=-1)
ms_filter_call_method(f,MS_VOLUME_SET_EA_THRESHOLD,&thres);
if (sustain!=-1)
ms_filter_call_method(f,MS_VOLUME_SET_EA_SUSTAIN,&sustain);
}
}
if (st->volsend){
ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres);
ms_filter_call_method(st->volsend,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&ng_floorgain);
}
if (st->volrecv){
/* parameters for a limited noise-gate effect, using echo limiter threshold */
float floorgain = 1/mic_gain;
ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&thres);
ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_FLOORGAIN,&floorgain);
}
parametrize_equalizer(lc,st);
if (lc->vtable.dtmf_received!=NULL){
/* replace by our default action*/
audio_stream_play_received_dtmfs(call->audiostream,FALSE);
rtp_session_signal_connect(call->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc);
}
}
static RtpProfile *make_profile(LinphoneCore *lc, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
int bw;
const MSList *elem;
RtpProfile *prof=rtp_profile_new("Call profile");
bool_t first=TRUE;
int remote_bw=0;
*used_pt=-1;
for(elem=desc->payloads;elem!=NULL;elem=elem->next){
PayloadType *pt=(PayloadType*)elem->data;
if (first) {
if (desc->type==SalAudio){
linphone_core_update_allocated_audio_bandwidth_in_call(lc,pt);
}
*used_pt=payload_type_get_number(pt);
first=FALSE;
}
if (desc->bandwidth>0) remote_bw=desc->bandwidth;
else if (md->bandwidth>0) {
/*case where b=AS is given globally, not per stream*/
remote_bw=md->bandwidth;
if (desc->type==SalVideo){
remote_bw-=lc->audio_bw;
}
}
if (desc->type==SalAudio){
bw=get_min_bandwidth(lc->up_audio_bw,remote_bw);
}else bw=get_min_bandwidth(lc->up_video_bw,remote_bw);
if (bw>0) pt->normal_bitrate=bw*1000;
else if (desc->type==SalAudio){
pt->normal_bitrate=-1;
}
if (desc->ptime>0){
char tmp[40];
snprintf(tmp,sizeof(tmp),"ptime=%i",desc->ptime);
payload_type_append_send_fmtp(pt,tmp);
}
rtp_profile_set_payload(prof,payload_type_get_number(pt),pt);
}
return prof;
}
void linphone_call_start_media_streams(LinphoneCall *call){
LinphoneCore *lc=call->core;
LinphoneAddress *me=linphone_core_get_primary_contact_parsed(lc);
const char *tool="linphone-" LINPHONE_VERSION;
char *cname;
int used_pt=-1;
if(call->audiostream == NULL)
{
ms_fatal("start_media_stream() called without prior init !");
return;
}
/* adjust rtp jitter compensation. It must be at least the latency of the sound card */
int jitt_comp=MAX(lc->sound_conf.latency,lc->rtp_conf.audio_jitt_comp);
if (call->media_start_time==0) call->media_start_time=time(NULL);
cname=linphone_address_as_string_uri_only(me);
{
const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpAvp,SalAudio);
if (stream){
MSSndCard *playcard=lc->sound_conf.lsd_card ?
lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard;
MSSndCard *captcard=lc->sound_conf.capt_sndcard;
const char *playfile=lc->play_file;
const char *recfile=lc->rec_file;
call->audio_profile=make_profile(lc,call->resultdesc,stream,&used_pt);
if (used_pt!=-1){
if (playcard==NULL) {
ms_warning("No card defined for playback !");
}
if (captcard==NULL) {
ms_warning("No card defined for capture !");
}
ms_message("streamdir is %i",stream->dir);
/*Replace soundcard filters by inactive file players or recorders
when placed in recvonly or sendonly mode*/
if (stream->port==0 || stream->dir==SalStreamRecvOnly){
captcard=NULL;
playfile=NULL;
}else if (stream->dir==SalStreamSendOnly){
playcard=NULL;
captcard=NULL;
recfile=NULL;
}
/*if playfile are supplied don't use soundcards*/
if (lc->use_files) {
captcard=NULL;
playcard=NULL;
}
audio_stream_start_full(
call->audiostream,
call->audio_profile,
stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr,
stream->port,
stream->port+1,
used_pt,
jitt_comp,
playfile,
recfile,
playcard,
captcard,
linphone_core_echo_cancellation_enabled(lc));
post_configure_audio_streams(call);
audio_stream_set_rtcp_information(call->audiostream, cname, tool);
}else ms_warning("No audio stream accepted ?");
}
}
#ifdef VIDEO_ENABLED
{
const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
SalProtoRtpAvp,SalVideo);
used_pt=-1;
/* shutdown preview */
if (lc->previewstream!=NULL) {
video_preview_stop(lc->previewstream);
lc->previewstream=NULL;
}
if (stream) {
const char *addr=stream->addr[0]!='\0' ? stream->addr : call->resultdesc->addr;
call->video_profile=make_profile(lc,call->resultdesc,stream,&used_pt);
if (used_pt!=-1){
VideoStreamDir dir=VideoStreamSendRecv;
MSWebCam *cam=lc->video_conf.device;
bool_t is_inactive=FALSE;
video_stream_set_sent_video_size(call->videostream,linphone_core_get_preferred_video_size(lc));
video_stream_enable_self_view(call->videostream,lc->video_conf.selfview);
if (stream->dir==SalStreamSendOnly && lc->video_conf.capture ){
cam=ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"Static picture");
dir=VideoStreamSendOnly;
}else if (stream->dir==SalStreamRecvOnly && lc->video_conf.display ){
dir=VideoStreamRecvOnly;
}else if (stream->dir==SalStreamSendRecv){
if (lc->video_conf.display && lc->video_conf.capture)
dir=VideoStreamSendRecv;
else if (lc->video_conf.display)
dir=VideoStreamRecvOnly;
else
dir=VideoStreamSendOnly;
}else{
ms_warning("video stream is inactive.");
/*either inactive or incompatible with local capabilities*/
is_inactive=TRUE;
}
if (!is_inactive){
video_stream_set_direction (call->videostream, dir);
video_stream_start(call->videostream,
call->video_profile, addr, stream->port,
stream->port+1,
used_pt, jitt_comp, cam);
video_stream_set_rtcp_information(call->videostream, cname,tool);
}
}else ms_warning("No video stream accepted.");
}else{
ms_warning("No valid video stream defined.");
}
}
#endif
goto end;
end:
ms_free(cname);
linphone_address_destroy(me);
}
static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
audio_stream_get_local_rtp_stats (st,&log->local_stats);
}
void linphone_call_stop_media_streams(LinphoneCall *call){
if (call->audiostream!=NULL) {
linphone_call_log_fill_stats (call->log,call->audiostream);
audio_stream_stop(call->audiostream);
call->audiostream=NULL;
}
#ifdef VIDEO_ENABLED
if (call->videostream!=NULL){
video_stream_stop(call->videostream);
call->videostream=NULL;
}
#endif
if (call->audio_profile){
rtp_profile_clear_all(call->audio_profile);
rtp_profile_destroy(call->audio_profile);
call->audio_profile=NULL;
}
if (call->video_profile){
rtp_profile_clear_all(call->video_profile);
rtp_profile_destroy(call->video_profile);
call->video_profile=NULL;
}
}

File diff suppressed because it is too large Load diff

View file

@ -97,14 +97,7 @@ void linphone_address_destroy(LinphoneAddress *u);
struct _SipSetupContext;
/**
* The LinphoneCall object represents a call issued or received by the LinphoneCore
**/
struct _LinphoneCall;
typedef struct _LinphoneCall LinphoneCall;
bool_t linphone_call_asked_to_autoanswer(struct _LinphoneCall *call);
/**
* Enum representing the direction of a call.
* @ingroup call_logs
@ -161,6 +154,28 @@ const rtp_stats_t *linphone_call_log_get_local_stats(const LinphoneCallLog *cl);
const rtp_stats_t *linphone_call_log_get_remote_stats(const LinphoneCallLog *cl);
char * linphone_call_log_to_str(LinphoneCallLog *cl);
/**
* The LinphoneCall object represents a call issued or received by the LinphoneCore
**/
struct _LinphoneCall;
typedef struct _LinphoneCall LinphoneCall;
enum _LinphoneCallState linphone_call_get_state(const LinphoneCall *call);
bool_t linphone_call_asked_to_autoanswer(LinphoneCall *call);
const LinphoneAddress * linphone_core_get_current_call_remote_address(struct _LinphoneCore *lc);
const LinphoneAddress * linphone_call_get_remote_address(const LinphoneCall *call);
char *linphone_call_get_remote_address_as_string(const LinphoneCall *call);
LinphoneCallDir linphone_call_get_dir(const LinphoneCall *call);
void linphone_call_ref(LinphoneCall *call);
void linphone_call_unref(LinphoneCall *call);
LinphoneCallLog *linphone_call_get_call_log(const LinphoneCall *call);
const char *linphone_call_get_refer_to(const LinphoneCall *call);
bool_t linphone_call_has_transfer_pending(const LinphoneCall *call);
void *linphone_call_get_user_pointer(LinphoneCall *call);
void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer);
typedef enum{
LinphoneSPWait,
LinphoneSPDeny,
@ -168,18 +183,18 @@ typedef enum{
}LinphoneSubscribePolicy;
typedef enum _LinphoneOnlineStatus{
LINPHONE_STATUS_OFFLINE,
LINPHONE_STATUS_ONLINE,
LINPHONE_STATUS_BUSY,
LINPHONE_STATUS_BERIGHTBACK,
LINPHONE_STATUS_AWAY,
LINPHONE_STATUS_ONTHEPHONE,
LINPHONE_STATUS_OUTTOLUNCH,
LINPHONE_STATUS_NOT_DISTURB,
LINPHONE_STATUS_MOVED,
LINPHONE_STATUS_ALT_SERVICE,
LINPHONE_STATUS_PENDING,
LINPHONE_STATUS_END
LinphoneStatusOffline,
LinphoneStatusOnline,
LinphoneStatusBusy,
LinphoneStatusBeRightBack,
LinphoneStatusAway,
LinphoneStatusOnThePhone,
LinphoneStatusOutToLunch,
LinphoneStatusDoNotDisturb,
LinphoneStatusMoved,
LinphoneStatusAltService,
LinphoneStatusPending,
LinphoneStatusEnd
}LinphoneOnlineStatus;
const char *linphone_online_status_to_string(LinphoneOnlineStatus ss);
@ -350,72 +365,62 @@ void linphone_chat_room_destroy(LinphoneChatRoom *cr);
void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud);
void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr);
/* describes the different groups of states */
typedef enum _gstate_group {
GSTATE_GROUP_POWER,
GSTATE_GROUP_REG,
GSTATE_GROUP_CALL
} gstate_group_t;
typedef enum _LinphoneCallState{
LinphoneCallIdle,
LinphoneCallIncomingReceived,
LinphoneCallOutgoingInit,
LinphoneCallOutgoingProgress,
LinphoneCallOutgoingRinging,
LinphoneCallOutgoingEarlyMedia,
LinphoneCallConnected,
LinphoneCallStreamsRunning,
LinphoneCallPausing,
LinphoneCallPaused,
LinphoneCallResuming,
LinphoneCallRefered,
LinphoneCallError,
LinphoneCallEnd,
} LinphoneCallState;
typedef enum _gstate {
/* states for GSTATE_GROUP_POWER */
GSTATE_POWER_OFF = 0, /* initial state */
GSTATE_POWER_STARTUP,
GSTATE_POWER_ON,
GSTATE_POWER_SHUTDOWN,
/* states for GSTATE_GROUP_REG */
GSTATE_REG_NONE = 10, /* initial state */
GSTATE_REG_OK,
GSTATE_REG_FAILED,
GSTATE_REG_PENDING, /* a registration request is ongoing*/
/* states for GSTATE_GROUP_CALL */
GSTATE_CALL_IDLE = 20, /* initial state */
GSTATE_CALL_OUT_INVITE,
GSTATE_CALL_OUT_CONNECTED,
GSTATE_CALL_IN_INVITE,
GSTATE_CALL_IN_CONNECTED,
GSTATE_CALL_END,
GSTATE_CALL_ERROR,
GSTATE_INVALID,
GSTATE_CALL_OUT_RINGING /*remote ringing*/
} gstate_t;
typedef enum _LinphoneGlobalState{
LinphoneGlobalOff,
LinphoneGlobalStartup,
LinphoneGlobalOn,
LinphoneGlobalShutdown
}LinphoneGlobalState;
struct _LinphoneGeneralState {
gstate_t old_state;
gstate_t new_state;
gstate_group_t group;
const char *message;
};
typedef struct _LinphoneGeneralState LinphoneGeneralState;
/* private: set a new state */
void gstate_new_state(struct _LinphoneCore *lc, gstate_t new_state, const char *message);
/*private*/
void gstate_initialize(struct _LinphoneCore *lc) ;
typedef enum _LinphoneRegistrationState{
LinphoneRegistrationNone,
LinphoneRegistrationProgress,
LinphoneRegistrationOk,
LinphoneRegistrationCleared,
LinphoneRegistrationFailed
}LinphoneRegistrationState;
/**
* @addtogroup initializing
* @{
**/
/**Call state notification callback prototype*/
typedef void (*LinphoneGlobalStateCb)(struct _LinphoneCore *lc, LinphoneGlobalState gstate, const char *message);
/**Call state notification callback prototype*/
typedef void (*LinphoneCallStateCb)(struct _LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *message);
/**Registration state notification callback prototype*/
typedef void (*LinphoneRegistrationStateCb)(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneCallState cstate, const char *message);
/** Callback prototype */
typedef void (*ShowInterfaceCb)(struct _LinphoneCore *lc);
/** Callback prototype */
typedef void (*InviteReceivedCb)(struct _LinphoneCore *lc, const char *from);
/** Callback prototype */
typedef void (*ByeReceivedCb)(struct _LinphoneCore *lc, const char *from);
/** Callback prototype */
typedef void (*DisplayStatusCb)(struct _LinphoneCore *lc, const char *message);
/** Callback prototype */
typedef void (*DisplayMessageCb)(struct _LinphoneCore *lc, const char *message);
/** Callback prototype */
typedef void (*DisplayUrlCb)(struct _LinphoneCore *lc, const char *message, const char *url);
/** Callback prototype */
typedef void (*DisplayQuestionCb)(struct _LinphoneCore *lc, const char *message);
/** Callback prototype */
typedef void (*LinphoneCoreCbFunc)(struct _LinphoneCore *lc,void * user_data);
/** Callback prototype */
typedef void (*NotifyReceivedCb)(struct _LinphoneCore *lc, const char *from, const char *msg);
typedef void (*NotifyReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call, const char *from, const char *event);
/** Callback prototype */
typedef void (*NotifyPresenceReceivedCb)(struct _LinphoneCore *lc, LinphoneFriend * fid);
/** Callback prototype */
@ -427,9 +432,7 @@ typedef void (*CallLogUpdated)(struct _LinphoneCore *lc, struct _LinphoneCallLog
/** Callback prototype */
typedef void (*TextMessageReceived)(struct _LinphoneCore *lc, LinphoneChatRoom *room, const char *from, const char *message);
/** Callback prototype */
typedef void (*GeneralStateChange)(struct _LinphoneCore *lc, LinphoneGeneralState *gstate);
/** Callback prototype */
typedef void (*DtmfReceived)(struct _LinphoneCore* lc, int dtmf);
typedef void (*DtmfReceived)(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf);
/** Callback prototype */
typedef void (*ReferReceived)(struct _LinphoneCore *lc, const char *refer_to);
/** Callback prototype */
@ -437,28 +440,26 @@ typedef void (*BuddyInfoUpdated)(struct _LinphoneCore *lc, LinphoneFriend *lf);
/**
* This structure holds all callbacks that the application should implement.
*
* None is mandatory.
**/
typedef struct _LinphoneVTable
{
ShowInterfaceCb show; /**< Notifies the application that it should show up*/
InviteReceivedCb inv_recv; /**< Notifies incoming calls */
ByeReceivedCb bye_recv; /**< Notify calls terminated by far end*/
typedef struct _LinphoneVTable{
LinphoneGlobalStateCb global_state_changed; /**<Notifies globlal state changes*/
LinphoneRegistrationStateCb registration_state_changed;/**<Notifies registration state changes*/
LinphoneCallStateCb call_state_changed;/**<Notifies call state changes*/
NotifyPresenceReceivedCb notify_presence_recv; /**< Notify received presence events*/
NewUnknownSubscriberCb new_unknown_subscriber; /**< Notify about unknown subscriber */
AuthInfoRequested auth_info_requested; /**< Ask the application some authentication information */
CallLogUpdated call_log_updated; /**< Notifies that call log list has been updated */
TextMessageReceived text_received; /**< A text message has been received */
DtmfReceived dtmf_received; /**< A dtmf has been received received */
ReferReceived refer_received; /**< An out of call refer was received */
BuddyInfoUpdated buddy_info_updated; /**< a LinphoneFriend's BuddyInfo has changed*/
NotifyReceivedCb notify_recv; /**< Other notifications*/
DisplayStatusCb display_status; /**< Callback that notifies various events with human readable text.*/
DisplayMessageCb display_message;/**< Callback to display a message to the user */
DisplayMessageCb display_warning;/** Callback to display a warning to the user */
DisplayUrlCb display_url;
DisplayQuestionCb display_question;
CallLogUpdated call_log_updated; /**< Notifies that call log list has been updated */
TextMessageReceived text_received; /**< A text message has been received */
GeneralStateChange general_state; /**< State notification callback */
DtmfReceived dtmf_received; /**< A dtmf has been received received */
ReferReceived refer_received; /**< A refer was received */
BuddyInfoUpdated buddy_info_updated; /**< a LinphoneFriend's BuddyInfo has changed*/
NotifyReceivedCb notify_recv; /**< Other notifications*/
ShowInterfaceCb show; /**< Notifies the application that it should show up*/
} LinphoneCoreVTable;
/**
@ -474,9 +475,9 @@ typedef struct _LCCallbackObj
typedef enum _LinphoneFirewallPolicy{
LINPHONE_POLICY_NO_FIREWALL,
LINPHONE_POLICY_USE_NAT_ADDRESS,
LINPHONE_POLICY_USE_STUN
LinphonePolicyNoFirewall,
LinphonePolicyUseNatAddress,
LinphonePolicyUseStun
} LinphoneFirewallPolicy;
typedef enum _LinphoneWaitingState{
@ -505,21 +506,29 @@ void linphone_core_iterate(LinphoneCore *lc);
LinphoneAddress * linphone_core_interpret_url(LinphoneCore *lc, const char *url);
int linphone_core_invite(LinphoneCore *lc, const char *url);
LinphoneCall * linphone_core_invite(LinphoneCore *lc, const char *url);
int linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr);
LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddress *addr);
int linphone_core_refer(LinphoneCore *lc, const char *url);
int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *refer_to);
bool_t linphone_core_inc_invite_pending(LinphoneCore*lc);
bool_t linphone_core_in_call(const LinphoneCore *lc);
LinphoneCall *linphone_core_get_current_call(LinphoneCore *lc);
LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc);
int linphone_core_accept_call(LinphoneCore *lc, const char *url);
int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_terminate_call(LinphoneCore *lc, const char *url);
int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_terminate_all_calls(LinphoneCore *lc);
int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call);
LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address);
void linphone_core_send_dtmf(LinphoneCore *lc,char dtmf);
@ -553,13 +562,6 @@ void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime);
*/
int linphone_core_get_download_ptime(LinphoneCore *lc);
#ifdef VINCENT_MAURY_RSVP
/* QoS functions */
int linphone_core_set_rpc_mode(LinphoneCore *lc, int on); /* on = 1 (RPC_ENABLE = 1) */
int linphone_core_set_rsvp_mode(LinphoneCore *lc, int on); /* on = 1 (RSVP_ENABLE = 1) */
int linphone_core_change_qos(LinphoneCore *lc, int answer); /* answer = 1 for yes, 0 for no */
#endif
/* returns a MSList of PayloadType */
const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc);
@ -573,12 +575,6 @@ bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, PayloadType *pt);
int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enable);
/*
* get payload type from mime type an clock rate
* @ingroup media_parameters
* iterates both audio an video
* return NULL if not found
*/
PayloadType* linphone_core_find_payload_type(LinphoneCore* lc, const char* type, int rate) ;
const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt);
@ -773,12 +769,12 @@ void linphone_core_use_files(LinphoneCore *lc, bool_t yesno);
void linphone_core_set_play_file(LinphoneCore *lc, const char *file);
void linphone_core_set_record_file(LinphoneCore *lc, const char *file);
gstate_t linphone_core_get_state(const LinphoneCore *lc, gstate_group_t group);
void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms);
void linphone_core_stop_dtmf(LinphoneCore *lc);
int linphone_core_get_current_call_duration(const LinphoneCore *lc);
const LinphoneAddress *linphone_core_get_remote_uri(LinphoneCore *lc);
const LinphoneAddress *linphone_core_get_remote_address(LinphoneCore *lc);
int linphone_core_get_mtu(const LinphoneCore *lc);
void linphone_core_set_mtu(LinphoneCore *lc, int mtu);
@ -824,8 +820,12 @@ void linphone_core_set_audio_transports(LinphoneCore *lc, RtpTransport *rtp, Rtp
int linphone_core_get_current_call_stats(LinphoneCore *lc, rtp_stats_t *local, rtp_stats_t *remote);
const MSList *linphone_core_get_calls(LinphoneCore *lc);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,52 @@
/*
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);
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(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, int rate, int nchannels);
LsdPlayer * linphone_sound_daemon_get_player(LinphoneSoundDaemon *lsd);
void linphone_sound_daemon_release_player(LinphoneSoundDaemon *lsd, LsdPlayer *lsdplayer);
void linphone_sound_daemon_stop_all_players(LinphoneSoundDaemon *obj);
void linphone_sound_daemon_release_all_players(LinphoneSoundDaemon *obj);
void linphone_core_use_sound_daemon(LinphoneCore *lc, LinphoneSoundDaemon *lsd);
void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj);
#endif

308
coreapi/lsd.c Normal file
View file

@ -0,0 +1,308 @@
/*
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 "private.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"
static struct _MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *obj);
#define MAX_BRANCHES 10
struct _LsdPlayer{
struct _LinphoneSoundDaemon *lsd;
MSFilter *player;
MSFilter *rateconv;
MSFilter *chanadapter;
LsdEndOfPlayCallback eop_cb;
int mixer_pin;
void *user_data;
bool_t loop;
bool_t pad[3];
};
struct _LinphoneSoundDaemon {
int out_rate;
int out_nchans;
MSFilter *mixer;
MSFilter *soundout;
MSTicker *ticker;
MSSndCard *proxycard;
LsdPlayer branches[MAX_BRANCHES];
};
static MSFilter *create_writer(MSSndCard *c){
LinphoneSoundDaemon *lsd=(LinphoneSoundDaemon*)c->data;
MSFilter *itcsink=ms_filter_new(MS_ITC_SINK_ID);
ms_filter_call_method(itcsink,MS_ITC_SINK_CONNECT,lsd->branches[0].player);
return 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=1;i<MAX_BRANCHES;++i){
LsdPlayer *b=&obj->branches[i];
MSFilter *p=b->player;
int state;
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;
}
}
ms_warning("No more free players !");
return NULL;
}
void linphone_sound_daemon_release_player(LinphoneSoundDaemon *obj, LsdPlayer * player){
int state;
ms_filter_call_method(player->player,MS_PLAYER_GET_STATE,&state);
if (state!=MSPlayerClosed){
ms_filter_call_method(player->player,MS_PLAYER_CLOSE,&state);
}
}
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;
}
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=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,mixer.filter,mixer.pin,-1);
p->mixer_pin=mixer.pin;
p->loop=FALSE;
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,mixer.filter,mixer.pin,-1);
ms_filter_destroy(p->player);
ms_filter_destroy(p->rateconv);
ms_filter_destroy(p->chanadapter);
}
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(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);
}
static void lsd_player_configure(LsdPlayer *b){
int rate,chans;
LinphoneSoundDaemon *lsd=b->lsd;
if (ms_filter_get_id(b->player)==MS_ITC_SOURCE_ID)
ms_message("Configuring branch coming from audio call...");
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_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_CHANNEL_ADAPTER_SET_OUTPUT_NCHANNELS,&lsd->out_nchans);
ms_message("player configured for rate=%i, channels=%i",rate,chans);
}
int lsd_player_play(LsdPlayer *b, const char *filename ){
int state;
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){
ms_warning("Could not play %s",filename);
return -1;
}
ms_filter_set_notify_callback (b->player,lsd_player_on_eop,b);
lsd_player_configure(b);
ms_filter_call_method_noarg (b->player,MS_PLAYER_START);
return 0;
}
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;
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 rate, int nchannels){
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->mixer=ms_filter_new(MS_AUDIO_MIXER_ID);
lsd->out_rate=rate;
lsd->out_nchans=nchannels;
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;
lsd_player_init(&lsd->branches[0],mp,MS_ITC_SOURCE_ID,lsd);
ms_filter_set_notify_callback(lsd->branches[0].player,(MSFilterNotifyFunc)lsd_player_configure,&lsd->branches[0]);
ms_filter_enable_synchronous_notifcations (lsd->branches[0].player,TRUE);
for(i=1;i<MAX_BRANCHES;++i){
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_message("LinphoneSoundDaemon started with rate=%i, nchannels=%i",rate,nchannels);
return lsd;
}
void linphone_sound_daemon_stop_all_players(LinphoneSoundDaemon *obj){
int i;
for(i=1;i<MAX_BRANCHES;++i){
lsd_player_stop(&obj->branches[i]);
}
}
void linphone_sound_daemon_release_all_players(LinphoneSoundDaemon *obj){
int i;
for(i=1;i<MAX_BRANCHES;++i){
linphone_sound_daemon_release_player(obj,&obj->branches[i]);
}
}
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;i<MAX_BRANCHES;++i){
mp.pin=i;
if (i!=0) linphone_sound_daemon_release_player(obj,&obj->branches[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);
}
MSSndCard *linphone_sound_daemon_get_proxy_card(LinphoneSoundDaemon *lsd){
return lsd->proxycard;
}
void linphone_core_use_sound_daemon(LinphoneCore *lc, LinphoneSoundDaemon *lsd){
if (lsd!=NULL){
lc->sound_conf.lsd_card=linphone_sound_daemon_get_proxy_card (lsd);
}else {
lc->sound_conf.lsd_card=NULL;
}
}

View file

@ -497,10 +497,10 @@ void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
lc->vtable.display_status(lc,_("Stun lookup in progress..."));
/*create the two audio and video RTP sockets, and send STUN message to our stun server */
sock1=create_socket(linphone_core_get_audio_port(lc));
sock1=create_socket(call->audio_port);
if (sock1<0) return;
if (video_enabled){
sock2=create_socket(linphone_core_get_video_port(lc));
sock2=create_socket(call->video_port);
if (sock2<0) return ;
}
sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,11,TRUE);

View file

@ -29,7 +29,10 @@ static PayloadType * find_payload_type_best_match(const MSList *l, const Payload
for (elem=l;elem!=NULL;elem=elem->next){
pt=(PayloadType*)elem->data;
if (strcasecmp(pt->mime_type,refpt->mime_type)==0 && pt->clock_rate==refpt->clock_rate){
/* the compare between G729 and G729A is for some stupid uncompliant phone*/
if ( (strcasecmp(pt->mime_type,refpt->mime_type)==0 ||
(strcasecmp(pt->mime_type, "G729") == 0 && strcasecmp(refpt->mime_type, "G729A") == 0 ))
&& pt->clock_rate==refpt->clock_rate){
candidate=pt;
/*good candidate, check fmtp for H264 */
if (strcasecmp(pt->mime_type,"H264")==0){
@ -85,6 +88,8 @@ static void initiate_outgoing(const SalStreamDescription *local_offer,
result->payloads=match_payloads(local_offer->payloads,remote_answer->payloads);
result->proto=local_offer->proto;
result->type=local_offer->type;
result->dir=local_offer->dir;
if (result->payloads && !only_telephone_event(result->payloads)){
strcpy(result->addr,remote_answer->addr);
result->port=remote_answer->port;
@ -102,6 +107,13 @@ static void initiate_incoming(const SalStreamDescription *local_cap,
result->payloads=match_payloads(local_cap->payloads,remote_offer->payloads);
result->proto=local_cap->proto;
result->type=local_cap->type;
if (remote_offer->dir==SalStreamSendOnly)
result->dir=SalStreamRecvOnly;
else if (remote_offer->dir==SalStreamRecvOnly){
result->dir=SalStreamSendOnly;
}else if (remote_offer->dir==SalStreamInactive){
result->dir=SalStreamInactive;
}else result->dir=SalStreamSendRecv;
if (result->payloads && !only_telephone_event(result->payloads)){
strcpy(result->addr,local_cap->addr);
result->port=local_cap->port;

View file

@ -92,36 +92,36 @@ void linphone_notify_recv(LinphoneCore *lc, SalOp *op, SalSubscribeState ss, Sal
char *tmp;
LinphoneFriend *lf;
LinphoneAddress *friend=NULL;
LinphoneOnlineStatus estatus=LINPHONE_STATUS_OFFLINE;
LinphoneOnlineStatus estatus=LinphoneStatusOffline;
switch(sal_status){
case SalPresenceOffline:
estatus=LINPHONE_STATUS_OFFLINE;
estatus=LinphoneStatusOffline;
break;
case SalPresenceOnline:
estatus=LINPHONE_STATUS_ONLINE;
estatus=LinphoneStatusOnline;
break;
case SalPresenceBusy:
estatus=LINPHONE_STATUS_BUSY;
estatus=LinphoneStatusBusy;
break;
case SalPresenceBerightback:
estatus=LINPHONE_STATUS_AWAY;
estatus=LinphoneStatusBeRightBack;
break;
case SalPresenceAway:
estatus=LINPHONE_STATUS_AWAY;
estatus=LinphoneStatusAway;
break;
case SalPresenceOnthephone:
estatus=LINPHONE_STATUS_ONTHEPHONE;
estatus=LinphoneStatusOnThePhone;
break;
case SalPresenceOuttolunch:
estatus=LINPHONE_STATUS_OUTTOLUNCH;
estatus=LinphoneStatusOutToLunch;
break;
case SalPresenceDonotdisturb:
estatus=LINPHONE_STATUS_BUSY;
estatus=LinphoneStatusDoNotDisturb;
break;
case SalPresenceMoved:
case SalPresenceAltService:
estatus=LINPHONE_STATUS_AWAY;
estatus=LinphoneStatusMoved;
break;
}
lf=linphone_find_friend_by_out_subscribe(lc->friends,op);
@ -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.");

View file

@ -54,14 +54,6 @@
#endif
#endif
typedef enum _LCState{
LCStateInit,
LCStatePreEstablishing,
LCStateRinging,
LCStateAVRunning
}LCState;
struct _LinphoneCall
{
struct _LinphoneCore *core;
@ -76,29 +68,36 @@ struct _LinphoneCall
char localip[LINPHONE_IPADDR_SIZE]; /* our best guess for local ipaddress for this call */
time_t start_time; /*time at which the call was initiated*/
time_t media_start_time; /*time at which it was accepted, media streams established*/
LCState state;
LinphoneCallState state;
int refcnt;
void * user_pointer;
int audio_port;
int video_port;
struct _AudioStream *audiostream; /**/
struct _VideoStream *videostream;
char *refer_to;
bool_t refer_pending;
bool_t media_pending;
bool_t audio_muted;
};
LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to);
LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op);
#define linphone_call_set_state(lcall,st) (lcall)->state=(st)
void linphone_call_destroy(struct _LinphoneCall *obj);
void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message);
/* private: */
LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *local, LinphoneAddress * remote);
void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call);
void linphone_call_log_completed(LinphoneCallLog *calllog, LinphoneCall *call, LinphoneCallStatus status);
void linphone_call_log_destroy(LinphoneCallLog *cl);
void linphone_core_init_media_streams(LinphoneCore *lc, LinphoneCall *call);
void linphone_auth_info_write_config(struct _LpConfig *config, LinphoneAuthInfo *obj, int pos);
void linphone_core_update_proxy_register(LinphoneCore *lc);
void linphone_core_refresh_subscribes(LinphoneCore *lc);
int linphone_core_abort_call(LinphoneCore *lc, LinphoneCall *call, const char *error);
int linphone_proxy_config_send_publish(LinphoneProxyConfig *cfg, LinphoneOnlineStatus os);
void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState rstate, const char *message);
int linphone_online_status_to_eXosip(LinphoneOnlineStatus os);
void linphone_friend_close_subscriptions(LinphoneFriend *lf);
@ -173,8 +172,11 @@ int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char
void linphone_core_text_received(LinphoneCore *lc, const char *from, const char *msg);
void linphone_core_start_media_streams(LinphoneCore *lc, struct _LinphoneCall *call);
void linphone_core_stop_media_streams(LinphoneCore *lc, struct _LinphoneCall *call);
void linphone_call_init_media_streams(LinphoneCall *call);
void linphone_call_start_media_streams(LinphoneCall *call);
void linphone_call_set_media_streams_dir(LinphoneCall *call, SalStreamDir dir);
void linphone_call_stop_media_streams(LinphoneCall *call);
const char * linphone_core_get_identity(LinphoneCore *lc);
const char * linphone_core_get_route(LinphoneCore *lc);
bool_t linphone_core_is_in_communication_with(LinphoneCore *lc, const char *to);
@ -183,7 +185,7 @@ void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float
void linphone_core_stop_waiting(LinphoneCore *lc);
int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy);
void linphone_core_start_pending_refered_calls(LinphoneCore *lc);
extern SalCallbacks linphone_sal_callbacks;
@ -297,6 +299,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;
@ -366,21 +369,20 @@ struct _LinphoneCore
struct _RingStream *ringstream;
time_t dmfs_playing_start_time;
LCCallbackObj preview_finished_cb;
struct _LinphoneCall *call; /* the current call, in the future it will be a list of calls (conferencing)*/
LinphoneCall *current_call; /* the current call */
MSList *calls; /* all the processed calls */
MSList *queued_calls; /* used by the autoreplier */
MSList *call_logs;
MSList *chatrooms;
int max_call_logs;
int missed_calls;
struct _AudioStream *audiostream; /**/
struct _VideoStream *videostream;
struct _VideoStream *previewstream;
struct _MSEventQueue *msevq;
RtpTransport *a_rtp,*a_rtcp;
MSList *bl_reqs;
MSList *subscribers; /* unknown subscribers */
int minutes_away;
LinphoneOnlineStatus presence_mode;
LinphoneOnlineStatus prev_mode;
char *alt_contact;
void *data;
char *play_file;
@ -391,9 +393,6 @@ struct _LinphoneCore
int dw_video_bw;
int up_video_bw;
int audio_bw;
gstate_t gstate_power;
gstate_t gstate_reg;
gstate_t gstate_call;
LinphoneWaitingCallback wait_cb;
void *wait_ctx;
bool_t use_files;
@ -403,7 +402,21 @@ struct _LinphoneCore
bool_t preview_finished;
bool_t auto_net_state_mon;
bool_t network_reachable;
bool_t audio_muted;
};
bool_t linphone_core_can_we_add_call(LinphoneCore *lc);
int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call);
int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call);
int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call);
int linphone_core_get_calls_nb(const LinphoneCore *lc);
void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message);
#define HOLD_OFF (0)
#define HOLD_ON (1)
#ifndef NB_MAX_CALLS
#define NB_MAX_CALLS (10)
#endif
#endif /* _PRIVATE_H */

View file

@ -263,6 +263,7 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){
static void linphone_proxy_config_register(LinphoneProxyConfig *obj){
const char *id_str;
if (obj->reg_identity!=NULL) id_str=obj->reg_identity;
else id_str=linphone_core_get_primary_contact(obj->lc);
if (obj->reg_sendregister){
@ -274,10 +275,10 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){
sal_op_set_contact(obj->op,contact);
ms_free(contact);
sal_op_set_user_pointer(obj->op,obj);
if (!sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires)) {
gstate_new_state(obj->lc,GSTATE_REG_PENDING,NULL);
if (sal_register(obj->op,obj->reg_proxy,obj->reg_identity,obj->expires)==0) {
linphone_proxy_config_set_state(obj,LinphoneRegistrationProgress,"Registration in progress");
} else {
gstate_new_state(obj->lc,GSTATE_REG_FAILED,NULL);
linphone_proxy_config_set_state(obj,LinphoneRegistrationFailed,"Registration failed");
}
}
}
@ -796,6 +797,12 @@ void * linphone_proxy_config_get_user_data(LinphoneProxyConfig *cr) {
return cr->user_data;
}
void linphone_proxy_config_set_state(LinphoneProxyConfig *cfg, LinphoneRegistrationState state, const char *message){
LinphoneCore *lc=cfg->lc;
if (lc && lc->vtable.registration_state_changed){
lc->vtable.registration_state_changed(lc,cfg,state,message);
}
}

View file

@ -62,11 +62,28 @@ const SalStreamDescription *sal_media_description_find_stream(const SalMediaDesc
return NULL;
}
bool_t sal_media_description_empty(SalMediaDescription *md){
bool_t sal_media_description_empty(const SalMediaDescription *md){
int i;
for(i=0;i<md->nstreams;++i){
const SalStreamDescription *ss=&md->streams[i];
if (ss->port!=0) return FALSE;
}
return TRUE;
}
void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){
int i;
for(i=0;i<md->nstreams;++i){
SalStreamDescription *ss=&md->streams[i];
if (ss->port!=0) return FALSE;
ss->dir=stream_dir;
}
}
bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){
int i;
for(i=0;i<md->nstreams;++i){
const SalStreamDescription *ss=&md->streams[i];
if (ss->dir!=stream_dir) return FALSE;
}
return TRUE;
}

View file

@ -86,6 +86,13 @@ typedef enum{
SalProtoRtpSavp
}SalMediaProto;
typedef enum{
SalStreamSendRecv,
SalStreamSendOnly,
SalStreamRecvOnly,
SalStreamInactive
}SalStreamDir;
typedef struct SalEndpointCandidate{
char addr[64];
int port;
@ -102,6 +109,7 @@ typedef struct SalStreamDescription{
int bandwidth;
int ptime;
SalEndpointCandidate candidates[SAL_ENDPOINT_CANDIDATE_MAX];
SalStreamDir dir;
} SalStreamDescription;
#define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4
@ -118,9 +126,11 @@ typedef struct SalMediaDescription{
SalMediaDescription *sal_media_description_new();
void sal_media_description_ref(SalMediaDescription *md);
void sal_media_description_unref(SalMediaDescription *md);
bool_t sal_media_description_empty(SalMediaDescription *md);
bool_t sal_media_description_empty(const SalMediaDescription *md);
bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir dir);
const SalStreamDescription *sal_media_description_find_stream(const SalMediaDescription *md,
SalMediaProto proto, SalStreamType type);
void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir);
/*this structure must be at the first byte of the SalOp structure defined by implementors*/
typedef struct SalOpBase{
@ -177,9 +187,9 @@ typedef void (*SalOnCallReceived)(SalOp *op);
typedef void (*SalOnCallRinging)(SalOp *op);
typedef void (*SalOnCallAccepted)(SalOp *op);
typedef void (*SalOnCallAck)(SalOp *op);
typedef void (*SalOnCallUpdated)(SalOp *op);
typedef void (*SalOnCallUpdating)(SalOp *op);/*< Called when a reINVITE is received*/
typedef void (*SalOnCallTerminated)(SalOp *op, const char *from);
typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details);
typedef void (*SalOnCallFailure)(SalOp *op, SalError error, SalReason reason, const char *details, int code);
typedef void (*SalOnAuthRequested)(SalOp *op, const char *realm, const char *username);
typedef void (*SalOnAuthSuccess)(SalOp *op, const char *realm, const char *username);
typedef void (*SalOnRegisterSuccess)(SalOp *op, bool_t registered);
@ -200,7 +210,7 @@ typedef struct SalCallbacks{
SalOnCallRinging call_ringing;
SalOnCallAccepted call_accepted;
SalOnCallAck call_ack;
SalOnCallUpdated call_updated;
SalOnCallUpdating call_updating;
SalOnCallTerminated call_terminated;
SalOnCallFailure call_failure;
SalOnAuthRequested auth_requested;
@ -263,8 +273,10 @@ void *sal_op_get_user_pointer(const SalOp *op);
int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc);
int sal_call(SalOp *h, const char *from, const char *to);
int sal_call_notify_ringing(SalOp *h);
/*accept an incoming call or, during a call accept a reINVITE*/
int sal_call_accept(SalOp*h);
int sal_call_decline(SalOp *h, SalReason reason, const char *redirection /*optional*/);
int sal_call_hold(SalOp *h, bool_t holdon);
SalMediaDescription * sal_call_get_final_media_description(SalOp *h);
int sal_refer(SalOp *h, const char *refer_to);
int sal_refer_accept(SalOp *h);
@ -306,5 +318,4 @@ void __sal_op_init(SalOp *b, Sal *sal);
void __sal_op_set_network_origin(SalOp *op, const char *origin /*a sip uri*/);
void __sal_op_free(SalOp *b);
#endif

View file

@ -284,8 +284,8 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){
ctx->callbacks.call_failure=(SalOnCallFailure)unimplemented_stub;
if (ctx->callbacks.call_terminated==NULL)
ctx->callbacks.call_terminated=(SalOnCallTerminated)unimplemented_stub;
if (ctx->callbacks.call_updated==NULL)
ctx->callbacks.call_updated=(SalOnCallUpdated)unimplemented_stub;
if (ctx->callbacks.call_updating==NULL)
ctx->callbacks.call_updating=(SalOnCallUpdating)unimplemented_stub;
if (ctx->callbacks.auth_requested==NULL)
ctx->callbacks.auth_requested=(SalOnAuthRequested)unimplemented_stub;
if (ctx->callbacks.auth_success==NULL)
@ -654,9 +654,13 @@ int sal_call_send_dtmf(SalOp *h, char dtmf){
}
int sal_call_terminate(SalOp *h){
int err;
eXosip_lock();
eXosip_call_terminate(h->cid,h->did);
err=eXosip_call_terminate(h->cid,h->did);
eXosip_unlock();
if (err!=0){
ms_warning("Exosip could not terminate the call: cid=%i did=%i", h->cid,h->did);
}
sal_remove_call(h->base.root,h);
h->cid=-1;
return 0;
@ -769,35 +773,27 @@ static void handle_reinvite(Sal *sal, eXosip_event_t *ev){
sal_media_description_unref(op->base.remote_media);
op->base.remote_media=NULL;
}
eXosip_lock();
eXosip_call_build_answer(ev->tid,200,&msg);
eXosip_unlock();
if (msg==NULL) return;
if (op->base.root->session_expires!=0){
if (op->supports_session_timers) osip_message_set_supported(msg, "timer");
}
if (op->base.contact){
_osip_list_set_empty(&msg->contacts,(void (*)(void*))osip_contact_free);
osip_message_set_contact(msg,op->base.contact);
if (op->result){
sal_media_description_unref(op->result);
op->result=NULL;
}
if (sdp){
op->sdp_offering=FALSE;
op->base.remote_media=sal_media_description_new();
sdp_to_media_description(sdp,op->base.remote_media);
sdp_message_free(sdp);
sdp_process(op);
if (op->sdp_answer!=NULL){
set_sdp(msg,op->sdp_answer);
sdp_message_free(op->sdp_answer);
op->sdp_answer=NULL;
}
sal->callbacks.call_updating(op);
}else {
op->sdp_offering=TRUE;
set_sdp_from_desc(msg,op->base.local_media);
eXosip_lock();
eXosip_call_build_answer(ev->tid,200,&msg);
if (msg!=NULL){
set_sdp_from_desc(msg,op->base.local_media);
eXosip_call_send_answer(ev->tid,200,msg);
}
eXosip_unlock();
}
eXosip_lock();
eXosip_call_send_answer(ev->tid,200,msg);
eXosip_unlock();
}
static void handle_ack(Sal *sal, eXosip_event_t *ev){
@ -816,7 +812,7 @@ static void handle_ack(Sal *sal, eXosip_event_t *ev){
sdp_message_free(sdp);
}
if (op->reinvite){
sal->callbacks.call_updated(op);
if (sdp) sal->callbacks.call_updating(op);
op->reinvite=FALSE;
}else{
sal->callbacks.call_ack(op);
@ -855,7 +851,8 @@ static int call_proceeding(Sal *sal, eXosip_event_t *ev){
eXosip_unlock();
return -1;
}
op->did=ev->did;
if (ev->did>0)
op->did=ev->did;
op->tid=ev->tid;
/* update contact if received and rport are set by the server
@ -938,7 +935,7 @@ static void call_released(Sal *sal, eXosip_event_t *ev){
}
op->cid=-1;
if (op->did==-1)
sal->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,NULL);
sal->callbacks.call_failure(op,SalErrorNoResponse,SalReasonUnknown,NULL, 487);
}
static int get_auth_data_from_response(osip_message_t *resp, const char **realm, const char **username){
@ -1100,7 +1097,7 @@ static bool_t call_failure(Sal *sal, eXosip_event_t *ev){
sr=SalReasonUnknown;
}else error=SalErrorNoResponse;
}
sal->callbacks.call_failure(op,error,sr,reason);
sal->callbacks.call_failure(op,error,sr,reason,code);
if (computedReason != NULL){
ms_free(computedReason);
}
@ -1777,3 +1774,32 @@ int sal_address_get_port_int(const SalAddress *uri) {
}
}
/*
* Send a re-Invite used to hold the current call
*/
int sal_call_hold(SalOp *h, bool_t holdon)
{
int err=0;
osip_message_t *reinvite=NULL;
if(eXosip_call_build_request(h->did,"INVITE",&reinvite) != OSIP_SUCCESS || reinvite==NULL)
return -1;
osip_message_set_subject(reinvite,osip_strdup("Phone Call Hold"));
osip_message_set_allow(reinvite, "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO");
if (h->base.root->session_expires!=0){
osip_message_set_header(reinvite, "Session-expires", "200");
osip_message_set_supported(reinvite, "timer");
}
//add something to say that the distant sip phone will be in sendonly/sendrecv mode
if (h->base.local_media){
h->sdp_offering=TRUE;
sal_media_description_set_dir(h->base.local_media, holdon ? SalStreamSendOnly : SalStreamSendRecv);
set_sdp_from_desc(reinvite,h->base.local_media);
}else h->sdp_offering=FALSE;
eXosip_lock();
err = eXosip_call_send_request(h->did, reinvite);
eXosip_unlock();
return err;
}

View file

@ -106,6 +106,23 @@ static int _sdp_message_get_a_ptime(sdp_message_t *sdp, int mline){
return 0;
}
static int _sdp_message_get_mline_dir(sdp_message_t *sdp, int mline){
int i;
sdp_attribute_t *attr;
for (i=0;(attr=sdp_message_attribute_get(sdp,mline,i))!=NULL;i++){
if (keywordcmp("sendrecv",attr->a_att_field)==0){
return SalStreamSendRecv;
}else if (keywordcmp("sendonly",attr->a_att_field)==0){
return SalStreamSendOnly;
}else if (keywordcmp("recvonly",attr->a_att_field)==0){
return SalStreamSendOnly;
}else if (keywordcmp("inactive",attr->a_att_field)==0){
return SalStreamInactive;
}
}
return SalStreamSendRecv;
}
static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc)
{
sdp_message_t *local;
@ -121,12 +138,21 @@ static sdp_message_t *create_generic_sdp(const SalMediaDescription *desc)
osip_strdup ("IN"), inet6 ? osip_strdup("IP6") : osip_strdup ("IP4"),
osip_strdup (desc->addr));
sdp_message_s_name_set (local, osip_strdup ("A conversation"));
sdp_message_c_connection_add (local, -1,
osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"),
osip_strdup (desc->addr), NULL, NULL);
if(!sal_media_description_has_dir (desc,SalStreamSendOnly))
{
sdp_message_c_connection_add (local, -1,
osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"),
osip_strdup (desc->addr), NULL, NULL);
}
else
{
sdp_message_c_connection_add (local, -1,
osip_strdup ("IN"), inet6 ? osip_strdup ("IP6") : osip_strdup ("IP4"),
inet6 ? osip_strdup ("::0") : osip_strdup ("0.0.0.0"), NULL, NULL);
}
sdp_message_t_time_descr_add (local, osip_strdup ("0"), osip_strdup ("0"));
if (desc->bandwidth>0) sdp_message_b_bandwidth_add (local, -1, osip_strdup ("AS"),
int_2char(desc->bandwidth));
int_2char(desc->bandwidth));
return local;
}
@ -158,6 +184,7 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription
const char *mt=desc->type==SalAudio ? "audio" : "video";
const MSList *elem;
const char *addr;
const char *dir="sendrecv";
int port;
if (desc->candidates[0].addr[0]!='\0'){
addr=desc->candidates[0].addr;
@ -186,6 +213,21 @@ static void add_line(sdp_message_t *msg, int lineno, const SalStreamDescription
for(elem=desc->payloads;elem!=NULL;elem=elem->next){
add_payload(msg, lineno, (PayloadType*)elem->data);
}
switch(desc->dir){
case SalStreamSendRecv:
dir="sendrecv";
break;
case SalStreamRecvOnly:
dir="recvonly";
break;
case SalStreamSendOnly:
dir="sendonly";
break;
case SalStreamInactive:
dir="inactive";
break;
}
sdp_message_a_attribute_add (msg, lineno, osip_strdup (dir),NULL);
}
sdp_message_t *media_description_to_sdp(const SalMediaDescription *desc){
@ -272,6 +314,7 @@ int sdp_to_media_description(sdp_message_t *msg, SalMediaDescription *desc){
for(j=0;(sbw=sdp_message_bandwidth_get(msg,i,j))!=NULL;++j){
if (strcasecmp(sbw->b_bwtype,"AS")==0) stream->bandwidth=atoi(sbw->b_bandwidth);
}
stream->dir=_sdp_message_get_mline_dir(msg,i);
/* for each payload type */
for (j=0;((number=sdp_message_m_payload_get (msg, i,j)) != NULL); j++){
const char *rtpmap,*fmtp;

103
coreapi/test_lsd.c Normal file
View file

@ -0,0 +1,103 @@
/*
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),p);
}
}
static void wait_a_bit(LinphoneCore *lc, int seconds){
time_t orig=time(NULL);
while(time(NULL)-orig<seconds){
/* we need to call iterate to receive notifications */
linphone_core_iterate(lc);
ms_usleep (50000);
}
}
int main(int argc, char *argv[]){
LinphoneCore *lc;
LinphoneCoreVTable vtable={0};
LinphoneSoundDaemon *lsd;
LsdPlayer *p;
linphone_core_enable_logs(stdout);
lc=linphone_core_new(&vtable,NULL,NULL,NULL);
lsd=linphone_sound_daemon_new (NULL,44100,1);
linphone_core_use_sound_daemon(lc,lsd);
/* start a play */
p=linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback (p,play_finished);
lsd_player_set_user_pointer (p,"share/hello8000.wav");
lsd_player_play (p,"share/hello8000.wav");
wait_a_bit (lc,2);
/*start another one */
p=linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback (p,play_finished);
lsd_player_set_user_pointer (p,"share/hello16000.wav");
lsd_player_enable_loop (p,TRUE);
lsd_player_play (p,"share/hello16000.wav");
/* after a few seconds decrease the volume */
wait_a_bit (lc,3);
lsd_player_set_gain (p,0.3);
wait_a_bit(lc,5);
/*now play some stereo music*/
p=linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback (p,play_finished);
lsd_player_set_user_pointer (p,"share/rings/rock.wav");
lsd_player_play(p,"share/rings/rock.wav");
wait_a_bit(lc,2);
/*now play some stereo music at 22khz in order to test
stereo resampling */
p=linphone_sound_daemon_get_player(lsd);
lsd_player_set_callback (p,play_finished);
lsd_player_set_user_pointer (p,"share/rings/bigben.wav");
lsd_player_play(p,"share/rings/bigben.wav");
wait_a_bit(lc,6);
/* now place an outgoing call if sip address argument is given */
if (argc>1){
linphone_core_invite(lc,argv[1]);
wait_a_bit(lc,10);
linphone_core_terminate_call(lc,NULL);
}
linphone_core_use_sound_daemon(lc,NULL);
linphone_sound_daemon_destroy(lsd);
linphone_core_destroy(lc);
return 0;
}

View file

@ -39,18 +39,18 @@ typedef struct _status_picture_tab_t{
} status_picture_tab_t;
status_picture_tab_t status_picture_tab[]={
{ LINPHONE_STATUS_ONLINE, "status-green.png" },
{ LINPHONE_STATUS_BUSY, "status-orange.png" },
{ LINPHONE_STATUS_BERIGHTBACK, "status-orange.png" },
{ LINPHONE_STATUS_AWAY, "status-orange.png" },
{ LINPHONE_STATUS_ONTHEPHONE, "status-orange.png" },
{ LINPHONE_STATUS_OUTTOLUNCH, "status-orange.png" },
{ LINPHONE_STATUS_NOT_DISTURB, "status-red.png" },
{ LINPHONE_STATUS_MOVED, "status-orange.png" },
{ LINPHONE_STATUS_ALT_SERVICE, "status-orange.png" },
{ LINPHONE_STATUS_OFFLINE, "status-offline.png" },
{ LINPHONE_STATUS_PENDING, "status-offline.png" },
{ LINPHONE_STATUS_END, NULL },
{ LinphoneStatusOnline, "status-green.png" },
{ LinphoneStatusBusy, "status-orange.png" },
{ LinphoneStatusBeRightBack, "status-orange.png" },
{ LinphoneStatusAway, "status-orange.png" },
{ LinphoneStatusOnThePhone, "status-orange.png" },
{ LinphoneStatusOutToLunch, "status-orange.png" },
{ LinphoneStatusDoNotDisturb, "status-red.png" },
{ LinphoneStatusMoved, "status-orange.png" },
{ LinphoneStatusAltService, "status-orange.png" },
{ LinphoneStatusOffline, "status-offline.png" },
{ LinphoneStatusPending, "status-offline.png" },
{ LinphoneStatusEnd, NULL },
};
static GdkPixbuf *create_status_picture(LinphoneOnlineStatus ss){
@ -132,7 +132,7 @@ static GtkWidget * create_presence_menu(){
GdkPixbuf *pbuf;
status_picture_tab_t *t;
for(t=status_picture_tab;t->img!=NULL;++t){
if (t->status==LINPHONE_STATUS_PENDING){
if (t->status==LinphoneStatusPending){
continue;
}
menu_item=gtk_image_menu_item_new_with_label(linphone_online_status_to_string(t->status));
@ -317,7 +317,7 @@ void linphone_gtk_show_friends(void){
continue;
}
}
if (!online_only || (linphone_friend_get_status(lf)!=LINPHONE_STATUS_OFFLINE)){
if (!online_only || (linphone_friend_get_status(lf)!=LinphoneStatusOffline)){
BuddyInfo *bi;
if (name==NULL || name[0]=='\0') display=uri;
gtk_list_store_append(store,&iter);

View file

@ -124,7 +124,7 @@ void linphone_gtk_in_call_view_set_in_call(){
GtkWidget *duration=linphone_gtk_get_widget(main_window,"in_call_duration");
GtkWidget *animation=linphone_gtk_get_widget(main_window,"in_call_animation");
GdkPixbufAnimation *pbuf=create_pixbuf_animation("incall_anim.gif");
const LinphoneAddress *uri=linphone_core_get_remote_uri(lc);
const LinphoneAddress *uri=linphone_core_get_current_call_remote_address(lc);
char *tmp=linphone_address_as_string(uri);
display_peer_name_in_label(callee,tmp);
ms_free(tmp);
@ -137,7 +137,9 @@ void linphone_gtk_in_call_view_set_in_call(){
g_object_unref(G_OBJECT(pbuf));
}else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_INFO,GTK_ICON_SIZE_DIALOG);
linphone_gtk_enable_mute_button(
GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"incall_mute")),TRUE);
GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"incall_mute")),TRUE);
linphone_gtk_enable_hold_button(
GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"hold_call")),TRUE);
}
void linphone_gtk_in_call_view_update_duration(int duration){
@ -175,6 +177,8 @@ void linphone_gtk_in_call_view_terminate(const char *error_msg){
}
linphone_gtk_enable_mute_button(
GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"incall_mute")),FALSE);
linphone_gtk_enable_hold_button(
GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,"hold_call")),FALSE);
g_timeout_add_seconds(2,(GSourceFunc)in_call_view_terminated,NULL);
}
@ -202,7 +206,54 @@ void linphone_gtk_mute_toggled(GtkToggleButton *button){
linphone_gtk_draw_mute_button(button,active);
}
void linphone_gtk_enable_mute_button(GtkToggleButton *button, gboolean sensitive){
void linphone_gtk_enable_mute_button(GtkToggleButton *button, gboolean sensitive)
{
gtk_widget_set_sensitive(GTK_WIDGET(button),sensitive);
linphone_gtk_draw_mute_button(button,FALSE);
}
void linphone_gtk_draw_hold_button(GtkToggleButton *button, gboolean active){
if (active){
GtkWidget *image=create_pixmap("hold_off.png");
gtk_button_set_label(GTK_BUTTON(button),_("HoldOff"));
if (image!=NULL) {
gtk_button_set_image(GTK_BUTTON(button),image);
gtk_widget_show(image);
}
}else{
GtkWidget *image=create_pixmap("hold_on.png");
gtk_button_set_label(GTK_BUTTON(button),_("HoldOn"));
if (image!=NULL) {
gtk_button_set_image(GTK_BUTTON(button),image);
gtk_widget_show(image);
}
}
}
void linphone_gtk_hold_toggled(GtkToggleButton *button){
gboolean active=gtk_toggle_button_get_active(button);
if(active)
{
LinphoneCall *call=linphone_core_get_current_call (linphone_gtk_get_core());
if (call==NULL) return;
linphone_core_pause_call(linphone_gtk_get_core(),call);
}
else
{
const MSList *calls=linphone_core_get_calls(linphone_gtk_get_core());
if (calls==NULL) return;
if (ms_list_size(calls)>1){
g_warning("Simultaneously calls not yet implemented in gtk ui.");
return;
}
/*we are supposed to have only one */
linphone_core_resume_call(linphone_gtk_get_core(),(LinphoneCall*)calls->data);
}
linphone_gtk_draw_hold_button(button,active);
}
void linphone_gtk_enable_hold_button(GtkToggleButton *button, gboolean sensitive){
gtk_widget_set_sensitive(GTK_WIDGET(button),sensitive);
linphone_gtk_draw_hold_button(button,FALSE);
}

View file

@ -92,6 +92,7 @@ void linphone_gtk_in_call_view_set_in_call(void);
void linphone_gtk_in_call_view_update_duration(int duration);
void linphone_gtk_in_call_view_terminate(const char *error_msg);
void linphone_gtk_enable_mute_button(GtkToggleButton *button, gboolean sensitive);
void linphone_gtk_enable_hold_button(GtkToggleButton *button, gboolean sensitive);
void linphone_gtk_show_login_frame(LinphoneProxyConfig *cfg);

View file

@ -42,8 +42,7 @@ static LinphoneCore *the_core=NULL;
static GtkWidget *the_ui=NULL;
static void linphone_gtk_show(LinphoneCore *lc);
static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from);
static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from);
static void linphone_gtk_inv_recv(LinphoneCore *lc, LinphoneCall *call);
static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid);
static void linphone_gtk_new_unknown_subscriber(LinphoneCore *lc, LinphoneFriend *lf, const char *url);
static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username);
@ -51,30 +50,11 @@ static void linphone_gtk_display_status(LinphoneCore *lc, const char *status);
static void linphone_gtk_display_message(LinphoneCore *lc, const char *msg);
static void linphone_gtk_display_warning(LinphoneCore *lc, const char *warning);
static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const char *url);
static void linphone_gtk_display_question(LinphoneCore *lc, const char *question);
static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl);
static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate);
static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to);
static void linphone_gtk_refer_received(LinphoneCore *lc, const char *refer_to);
static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg);
static gboolean linphone_gtk_auto_answer(GtkWidget *incall_window);
static LinphoneCoreVTable vtable={
.show=linphone_gtk_show,
.inv_recv=linphone_gtk_inv_recv,
.bye_recv=linphone_gtk_bye_recv,
.notify_presence_recv=linphone_gtk_notify_recv,
.new_unknown_subscriber=linphone_gtk_new_unknown_subscriber,
.auth_info_requested=linphone_gtk_auth_info_requested,
.display_status=linphone_gtk_display_status,
.display_message=linphone_gtk_display_message,
.display_warning=linphone_gtk_display_warning,
.display_url=linphone_gtk_display_url,
.display_question=linphone_gtk_display_question,
.call_log_updated=linphone_gtk_call_log_updated,
.text_received=linphone_gtk_text_received,
.general_state=linphone_gtk_general_state,
.refer_received=linphone_gtk_refer_received,
.buddy_info_updated=linphone_gtk_buddy_info_updated
};
static gboolean verbose=0;
static gboolean auto_answer = 0;
@ -211,6 +191,22 @@ static const char *linphone_gtk_get_factory_config_file(){
static void linphone_gtk_init_liblinphone(const char *config_file,
const char *factory_config_file) {
LinphoneCoreVTable vtable={0};
vtable.call_state_changed=linphone_gtk_call_state_changed;
vtable.show=linphone_gtk_show;
vtable.notify_presence_recv=linphone_gtk_notify_recv;
vtable.new_unknown_subscriber=linphone_gtk_new_unknown_subscriber;
vtable.auth_info_requested=linphone_gtk_auth_info_requested;
vtable.display_status=linphone_gtk_display_status;
vtable.display_message=linphone_gtk_display_message;
vtable.display_warning=linphone_gtk_display_warning;
vtable.display_url=linphone_gtk_display_url;
vtable.call_log_updated=linphone_gtk_call_log_updated;
vtable.text_received=linphone_gtk_text_received;
vtable.refer_received=linphone_gtk_refer_received;
vtable.buddy_info_updated=linphone_gtk_buddy_info_updated;
linphone_core_set_user_agent("Linphone", LINPHONE_VERSION);
the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL);
linphone_core_set_waiting_callback(the_core,linphone_gtk_wait,NULL);
@ -390,7 +386,7 @@ static void set_video_window_decorations(GdkWindow *w){
gdk_window_set_keep_above(w, FALSE);
}else{
LinphoneAddress *uri =
linphone_address_clone(linphone_core_get_remote_uri(linphone_gtk_get_core()));
linphone_address_clone(linphone_core_get_current_call_remote_address(linphone_gtk_get_core()));
char *display_name;
linphone_address_clean(uri);
@ -588,7 +584,7 @@ static void linphone_gtk_call_started(GtkWidget *mw){
static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar));
if (linphone_core_invite(linphone_gtk_get_core(),entered)==0) {
if (linphone_core_invite(linphone_gtk_get_core(),entered)!=NULL) {
completion_add_text(GTK_ENTRY(uri_bar),entered);
}else{
linphone_gtk_call_terminated(NULL);
@ -643,7 +639,9 @@ void linphone_gtk_uri_bar_activate(GtkWidget *w){
void linphone_gtk_terminate_call(GtkWidget *button){
linphone_core_terminate_call(linphone_gtk_get_core(),NULL);
const MSList *elem=linphone_core_get_calls(linphone_gtk_get_core());
if (elem==NULL) return;
linphone_core_terminate_call(linphone_gtk_get_core(),(LinphoneCall*)elem->data);
}
void linphone_gtk_decline_call(GtkWidget *button){
@ -704,10 +702,11 @@ static void linphone_gtk_show(LinphoneCore *lc){
linphone_gtk_show_main_window();
}
static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from){
static void linphone_gtk_inv_recv(LinphoneCore *lc, LinphoneCall *call){
GtkWidget *w=linphone_gtk_create_window("incoming_call");
GtkWidget *label;
gchar *msg;
char *from=linphone_call_get_remote_address_as_string(call);
if (auto_answer){
g_timeout_add(2000,(GSourceFunc)linphone_gtk_auto_answer,w);
@ -727,10 +726,7 @@ static void linphone_gtk_inv_recv(LinphoneCore *lc, const char *from){
g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"incoming_call",w);
gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"uribar")),
from);
}
static void linphone_gtk_bye_recv(LinphoneCore *lc, const char *from){
ms_free(from);
}
static void linphone_gtk_notify_recv(LinphoneCore *lc, LinphoneFriend * fid){
@ -868,31 +864,29 @@ static void linphone_gtk_display_url(LinphoneCore *lc, const char *msg, const ch
linphone_gtk_display_something(GTK_MESSAGE_INFO,richtext);
}
static void linphone_gtk_display_question(LinphoneCore *lc, const char *question){
linphone_gtk_display_something(GTK_MESSAGE_QUESTION,question);
}
static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl){
GtkWidget *w=(GtkWidget*)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"call_logs");
if (w) linphone_gtk_call_log_update(w);
}
static void linphone_gtk_general_state(LinphoneCore *lc, LinphoneGeneralState *gstate){
switch(gstate->new_state){
case GSTATE_CALL_OUT_CONNECTED:
case GSTATE_CALL_IN_CONNECTED:
static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg){
switch(cs){
case LinphoneCallConnected:
if (linphone_gtk_use_in_call_view())
linphone_gtk_in_call_view_set_in_call();
linphone_gtk_enable_mute_button(
GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")),
TRUE);
break;
case GSTATE_CALL_ERROR:
linphone_gtk_call_terminated(gstate->message);
case LinphoneCallError:
linphone_gtk_call_terminated(msg);
break;
case GSTATE_CALL_END:
case LinphoneCallEnd:
linphone_gtk_call_terminated(NULL);
break;
case LinphoneCallIncomingReceived:
linphone_gtk_inv_recv (lc,call);
break;
default:
break;
}
@ -1145,6 +1139,8 @@ static void linphone_gtk_init_main_window(){
"main_mute")),FALSE);
linphone_gtk_enable_mute_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,
"incall_mute")),FALSE);
linphone_gtk_enable_hold_button(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(main_window,
"hold_call")),FALSE);
if (!linphone_gtk_use_in_call_view()) {
gtk_widget_show(linphone_gtk_get_widget(main_window, "main_mute"));
}

View file

@ -1190,6 +1190,7 @@ Fiber Channel</property>
<child>
<widget class="GtkHButtonBox" id="hbuttonbox4">
<property name="visible">True</property>
<property name="layout_style">spread</property>
<child>
<widget class="GtkToggleButton" id="incall_mute">
<property name="label" translatable="yes">Mute</property>
@ -1205,6 +1206,21 @@ Fiber Channel</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkToggleButton" id="hold_call">
<property name="label" translatable="yes">HoldOn</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="toggled" handler="linphone_gtk_hold_toggled"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>

View file

@ -119,17 +119,17 @@ void linphone_gtk_video_port_changed(GtkWidget *w){
void linphone_gtk_no_firewall_toggled(GtkWidget *w){
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)))
linphone_core_set_firewall_policy(linphone_gtk_get_core(),LINPHONE_POLICY_NO_FIREWALL);
linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyNoFirewall);
}
void linphone_gtk_use_nat_address_toggled(GtkWidget *w){
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)))
linphone_core_set_firewall_policy(linphone_gtk_get_core(),LINPHONE_POLICY_USE_NAT_ADDRESS);
linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseNatAddress);
}
void linphone_gtk_use_stun_toggled(GtkWidget *w){
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)))
linphone_core_set_firewall_policy(linphone_gtk_get_core(),LINPHONE_POLICY_USE_STUN);
linphone_core_set_firewall_policy(linphone_gtk_get_core(),LinphonePolicyUseStun);
}
void linphone_gtk_mtu_changed(GtkWidget *w){
@ -762,13 +762,13 @@ void linphone_gtk_show_parameters(void){
if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"stun_server")),tmp);
pol=linphone_core_get_firewall_policy(lc);
switch(pol){
case LINPHONE_POLICY_NO_FIREWALL:
case LinphonePolicyNoFirewall:
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"no_nat")),TRUE);
break;
case LINPHONE_POLICY_USE_NAT_ADDRESS:
case LinphonePolicyUseNatAddress:
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_nat_address")),TRUE);
break;
case LINPHONE_POLICY_USE_STUN:
case LinphonePolicyUseStun:
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_stun")),TRUE);
break;
}

@ -1 +1 @@
Subproject commit 332d79209b333bd8ded5b16a7b9dcfe2c0aedc63
Subproject commit ea7ca97aaaa6f191dfec112f137fb048a4ef2139

View file

@ -3,6 +3,7 @@
pixmapdir=$(datadir)/pixmaps/linphone
pixmap_DATA= \
hold_on.png hold_off.png \
mic_muted.png mic_active.png \
linphone-3-250x130.png linphone-3.png linphone2-57x57.png \
linphone.png linphone-banner.png \

BIN
pixmaps/hold_off.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
pixmaps/hold_on.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -72,3 +72,5 @@ mediastreamer2/src/audiomixer.c
mediastreamer2/src/chanadapt.c
mediastreamer2/src/itc.c
mediastreamer2/src/extdisplay.c
mediastreamer2/src/msiounit.c