Commit d70a6910 authored by Yann Diorcet's avatar Yann Diorcet
Browse files

Merge branch 'master' into belle-sip

Conflicts:
	coreapi/sal.c
	coreapi/sal.h
parents e9398144 f36aac6d
......@@ -1965,7 +1965,7 @@ static int lpc_cmd_duration(LinphoneCore *lc, char *args){
for(;elem!=NULL;elem=elem->next){
if (elem->next==NULL){
cl=(LinphoneCallLog*)elem->data;
linphonec_out("%i seconds\n",cl->duration);
linphonec_out("%i seconds\n",linphone_call_log_get_duration(cl));
}
}
return 1;
......
......@@ -16,7 +16,7 @@ CLEANFILES=$(GITVERSION_FILE)
## Process this file with automake to produce Makefile.in
linphone_includedir=$(includedir)/linphone
linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonecore_utils.h ../config.h lpconfig.h sipsetup.h
linphone_include_HEADERS=linphonecore.h linphonefriend.h linphonecore_utils.h lpconfig.h sipsetup.h
if BUILD_TUNNEL
linphone_include_HEADERS+=linphone_tunnel.h
......
......@@ -842,10 +842,10 @@ static bool_t is_duplicate_msg(LinphoneCore *lc, const char *msg_id){
}
static void text_received(Sal *sal, const SalMessage *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal);
static void text_received(SalOp *op, const SalMessage *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
if (is_duplicate_msg(lc,msg->message_id)==FALSE){
linphone_core_message_received(lc,msg);
linphone_core_message_received(lc,op,msg);
}
}
......
......@@ -25,8 +25,19 @@
#include "linphonecore.h"
#include "private.h"
#include "lpconfig.h"
LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to){
/**
* @addtogroup chatroom
* @{
*/
/**
* Create a new chat room for messaging from a sip uri like sip:joe@sip.linphone.org
* @param lc #LinphoneCore object
* @param to destination address for messages
* @return #LinphoneChatRoom where messaging can take place.
*/
LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to){
LinphoneAddress *parsed_url=NULL;
if ((parsed_url=linphone_core_interpret_url(lc,to))!=NULL){
......@@ -38,16 +49,18 @@
return cr;
}
return NULL;
}
}
void linphone_chat_room_destroy(LinphoneChatRoom *cr){
/**
* Destroy a LinphoneChatRoom.
* @param cr #LinphoneChatRoom object
*/
void linphone_chat_room_destroy(LinphoneChatRoom *cr){
LinphoneCore *lc=cr->lc;
lc->chatrooms=ms_list_remove(lc->chatrooms,(void *) cr);
linphone_address_destroy(cr->peer_url);
ms_free(cr->peer);
}
}
static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage* msg){
const char *route=NULL;
......@@ -56,7 +69,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
LinphoneCall *call;
char* content_type;
if (lp_config_get_int(cr->lc->config,"sip","chat_use_call_dialogs",1)){
if (lp_config_get_int(cr->lc->config,"sip","chat_use_call_dialogs",0)){
if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL){
if (call->state==LinphoneCallConnected ||
call->state==LinphoneCallStreamsRunning ||
......@@ -74,21 +87,30 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
op = sal_op_new(cr->lc->sal);
sal_op_set_route(op,route);
sal_op_set_user_pointer(op, msg); /*if out of call, directly store msg*/
if (msg->custom_headers){
sal_op_set_custom_header(op,msg->custom_headers);
msg->custom_headers=NULL; /*transfered to the SalOp*/
}
}
if (msg->external_body_url) {
content_type=ms_strdup_printf("message/external-body; access-type=URL; URL=\"%s\"",msg->external_body_url);
sal_message_send(op,identity,cr->peer,content_type,NULL);
sal_message_send(op,identity,cr->peer,content_type, NULL);
ms_free(content_type);
} else {
sal_text_send(op, identity, cr->peer, msg->message);
sal_text_send(op, identity, cr->peer,msg->message);
}
}
/**
* Send a message to peer member of this chat room.
* @deprecated linphone_chat_room_send_message2() gives more control on the message expedition.
* @param cr #LinphoneChatRoom object
* @param msg message to be sent
*/
void linphone_chat_room_send_message(LinphoneChatRoom *cr, const char *msg) {
_linphone_chat_room_send_message(cr,linphone_chat_room_create_message(cr,msg));
}
bool_t linphone_chat_room_matches(LinphoneChatRoom *cr, const LinphoneAddress *from){
if (linphone_address_get_username(cr->peer_url) && linphone_address_get_username(from) &&
strcmp(linphone_address_get_username(cr->peer_url),linphone_address_get_username(from))==0) return TRUE;
......@@ -103,12 +125,14 @@ void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc,
}
void linphone_core_message_received(LinphoneCore *lc, const SalMessage *sal_msg){
void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessage *sal_msg){
MSList *elem;
LinphoneChatRoom *cr=NULL;
LinphoneAddress *addr;
char *cleanfrom;
LinphoneChatMessage* msg;
const SalCustomHeader *ch;
addr=linphone_address_new(sal_msg->from);
linphone_address_clean(addr);
for(elem=lc->chatrooms;elem!=NULL;elem=ms_list_next(elem)){
......@@ -126,6 +150,8 @@ void linphone_core_message_received(LinphoneCore *lc, const SalMessage *sal_msg)
msg = linphone_chat_room_create_message(cr, sal_msg->text);
linphone_chat_message_set_from(msg, cr->peer_url);
msg->time=sal_msg->time;
ch=sal_op_get_custom_header(op);
if (ch) msg->custom_headers=sal_custom_header_clone(ch);
if (sal_msg->url) {
linphone_chat_message_set_external_body_url(msg, sal_msg->url);
......@@ -135,44 +161,66 @@ void linphone_core_message_received(LinphoneCore *lc, const SalMessage *sal_msg)
ms_free(cleanfrom);
}
/**
* Returns back pointer to LinphoneCore object.
**/
LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr){
return cr->lc;
}
LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg){
return msg->chat_room;
}
/**
* Assign a user pointer to the chat room.
**/
void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud){
cr->user_data=ud;
}
/**
* Retrieve the user pointer associated with the chat room.
**/
void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr){
return cr->user_data;
}
/**
* get peer address \link linphone_core_create_chat_room() associated to \endlink this #LinphoneChatRoom
* @param cr #LinphoneChatRoom object
* @return #LinphoneAddress peer address
*/
const LinphoneAddress* linphone_chat_room_get_peer_address(LinphoneChatRoom *cr) {
return cr->peer_url;
}
LinphoneChatMessage* linphone_chat_room_create_message(const LinphoneChatRoom *cr,const char* message) {
/**
* Create a message attached to a dedicated chat room;
* @param cr the chat room.
* @param message text message, NULL if absent.
* @return a new #LinphoneChatMessage
*/
LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, const char* message) {
LinphoneChatMessage* msg = ms_new0(LinphoneChatMessage,1);
msg->chat_room=(LinphoneChatRoom*)cr;
msg->message=message?ms_strdup(message):NULL;
return msg;
}
void linphone_chat_message_destroy(LinphoneChatMessage* msg) {
if (msg->message) ms_free(msg->message);
if (msg->external_body_url) ms_free(msg->external_body_url);
if (msg->from) linphone_address_destroy(msg->from);
ms_free(msg);
}
void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb,void* ud) {
/**
* Send a message to peer member of this chat room.
* @param cr #LinphoneChatRoom object
* @param msg #LinphoneChatMessage message to be sent
* @param status_cb LinphoneChatMessageStateChangeCb status callback invoked when message is delivered or could not be delivered. May be NULL
* @param ud user data for the status cb.
* @note The LinphoneChatMessage must not be destroyed until the the callback is called.
*/
void linphone_chat_room_send_message2(LinphoneChatRoom *cr, LinphoneChatMessage* msg,LinphoneChatMessageStateChangeCb status_cb, void* ud) {
msg->cb=status_cb;
msg->cb_ud=ud;
_linphone_chat_room_send_message(cr, msg);
}
/**
* Returns a #LinphoneChatMessageState as a string.
*/
const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState state) {
switch (state) {
case LinphoneChatMessageStateIdle:return "LinphoneChatMessageStateIdle";
......@@ -184,53 +232,112 @@ const char* linphone_chat_message_state_to_string(const LinphoneChatMessageState
}
char* linphone_chat_message_get_message(LinphoneChatMessage* msg) {
return msg->message;
/**
* Returns the chatroom this message belongs to.
**/
LinphoneChatRoom* linphone_chat_message_get_chat_room(LinphoneChatMessage *msg){
return msg->chat_room;
}
/**
* Returns the peer (remote) address for the message.
**/
const LinphoneAddress* linphone_chat_message_get_peer_address(LinphoneChatMessage *msg) {
return linphone_chat_room_get_peer_address(msg->chat_room);
}
/**
* user pointer set function
*User pointer set function
*/
void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void* ud) {
message->message_userdata=ud;
}
/**
* user pointer get function
* User pointer get function
*/
void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message) {
return message->message_userdata;
}
/**
* Linphone message can carry external body as defined by rfc2017
* @param message #LinphoneChatMessage
* @return external body url or NULL if not present.
*/
const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message) {
return message->external_body_url;
}
/**
* Linphone message can carry external body as defined by rfc2017
*
* @param message a LinphoneChatMessage
* @param url ex: access-type=URL; URL="http://www.foo.com/file"
*/
void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url) {
if (message->external_body_url) {
ms_free(message->external_body_url);
}
message->external_body_url=url?ms_strdup(url):NULL;
}
/**
* Set origin of the message
*@param message #LinphoneChatMessage obj
*@param from #LinphoneAddress origin of this message (copied)
*/
void linphone_chat_message_set_from(LinphoneChatMessage* message, const LinphoneAddress* from) {
if(message->from) linphone_address_destroy(message->from);
message->from=linphone_address_clone(from);
}
/**
* Get origin of the message
*@param message #LinphoneChatMessage obj
*@return #LinphoneAddress
*/
LinphoneAddress* linphone_chat_message_get_from(const LinphoneChatMessage* message) {
return message->from;
}
/**
* Get the time the message was sent.
*/
time_t linphone_chat_message_get_time(const LinphoneChatMessage* message) {
return message->time;
}
/**
* Get text part of this message
* @return text or NULL if no text.
*/
const char * linphone_chat_message_get_text(const LinphoneChatMessage* message) {
return message->message;
}
/**
* Add custom headers to the message.
* @param message the message
* @param header_name name of the header_name
* @param header_value header value
**/
void linphone_chat_message_add_custom_header(LinphoneChatMessage* message, const char *header_name, const char *header_value){
message->custom_headers=sal_custom_header_append(message->custom_headers,header_name,header_value);
}
/**
* Retrieve a custom header value given its name.
* @param message the message
* @param header_name header name searched
**/
const char * linphone_chat_message_get_custom_header(LinphoneChatMessage* message, const char *header_name){
return sal_custom_header_find(message->custom_headers,header_name);
}
/**
* Duplicate a LinphoneChatMessage
**/
LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg) {
/*struct _LinphoneChatMessage {
char* message;
......@@ -250,3 +357,21 @@ LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg)
if (msg->from) new_message->from=linphone_address_clone(msg->from);
return new_message;
}
/**
* Destroys a LinphoneChatMessage.
**/
void linphone_chat_message_destroy(LinphoneChatMessage* msg) {
if (msg->message) ms_free(msg->message);
if (msg->external_body_url) ms_free(msg->external_body_url);
if (msg->from) linphone_address_destroy(msg->from);
if (msg->custom_headers) sal_custom_header_free(msg->custom_headers);
ms_free(msg);
}
/**
* @}
*/
......@@ -161,6 +161,7 @@ float linphone_core_get_conference_local_input_volume(LinphoneCore *lc){
*
* If this is the first call that enters the conference, the virtual conference will be created automatically.
* If the local user was actively part of the call (ie not in paused state), then the local user is automatically entered into the conference.
* If the call was in paused state, then it is automatically resumed when entering into the conference.
*
* @returns 0 if successful, -1 otherwise.
**/
......@@ -256,10 +257,13 @@ static int convert_conference_to_call(LinphoneCore *lc){
* @param call a call that has been previously merged into the conference.
*
* After removing the remote participant belonging to the supplied call, the call becomes a normal call in paused state.
* If one single remote participant is left alone in the conference after the removal, then it is
* automatically removed from the conference and put into a simple call, like before entering the conference.
* If one single remote participant is left alone together with the local user in the conference after the removal, then the conference is
* automatically transformed into a simple call in StreamsRunning state.
* The conference's resources are then automatically destroyed.
*
* In other words, unless linphone_core_leave_conference() is explicitely called, the last remote participant of a conference is automatically
* put in a simple call in running state.
*
* @returns 0 if successful, -1 otherwise.
**/
int linphone_core_remove_from_conference(LinphoneCore *lc, LinphoneCall *call){
......
......@@ -471,7 +471,9 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
call->core=lc;
linphone_core_get_local_ip(lc,linphone_address_get_domain(to),call->localip);
linphone_call_init_common(call,from,to);
call->params=*params;
_linphone_call_params_copy(&call->params,params);
sal_op_set_custom_header(call->op,call->params.custom_headers);
if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
call->ice_session = ice_session_new();
ice_session_set_role(call->ice_session, IR_Controlling);
......@@ -733,7 +735,7 @@ static void linphone_call_destroy(LinphoneCall *obj)
if (obj->auth_token) {
ms_free(obj->auth_token);
}
linphone_call_params_uninit(&obj->params);
ms_free(obj);
}
......@@ -768,7 +770,9 @@ void linphone_call_unref(LinphoneCall *obj){
/**
* Returns current parameters associated to the call.
**/
const LinphoneCallParams * linphone_call_get_current_params(const LinphoneCall *call){
const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){
if (call->params.record_file)
call->current_params.record_file=call->params.record_file;
return &call->current_params;
}
......@@ -806,6 +810,7 @@ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){
cp->low_bandwidth=TRUE;
}
}
cp->custom_headers=(SalCustomHeader*)sal_op_get_custom_header(call->op);
return cp;
}
}
......@@ -959,6 +964,18 @@ void linphone_call_enable_camera (LinphoneCall *call, bool_t enable){
#endif
}
#ifdef VIDEO_ENABLED
/**
* Request remote side to send us a Video Fast Update.
**/
void linphone_call_send_vfu_request(LinphoneCall *call)
{
if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
sal_call_send_vfu_request(call->op);
}
#endif
/**
* Take a photo of currently received video and write it into a jpeg file.
**/
......@@ -987,10 +1004,17 @@ void linphone_call_params_enable_video(LinphoneCallParams *cp, bool_t enabled){
cp->has_video=enabled;
}
/**
* Returns the audio codec used in the call, described as a PayloadType structure.
**/
const PayloadType* linphone_call_params_get_used_audio_codec(const LinphoneCallParams *cp) {
return cp->audio_codec;
}
/**
* Returns the video codec used in the call, described as a PayloadType structure.
**/
const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallParams *cp) {
return cp->video_codec;
}
......@@ -1027,10 +1051,16 @@ bool_t linphone_call_params_video_enabled(const LinphoneCallParams *cp){
return cp->has_video;
}
/**
* Returns kind of media encryption selected for the call.
**/
enum LinphoneMediaEncryption linphone_call_params_get_media_encryption(const LinphoneCallParams *cp) {
return cp->media_encryption;
}
/**
* Set requested media encryption for a call.
**/
void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, enum LinphoneMediaEncryption e) {
cp->media_encryption = e;
}
......@@ -1043,6 +1073,9 @@ void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, boo
cp->real_early_media=enabled;
}
/**
* Indicates whether sending of early media was enabled.
**/
bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp){
return cp->real_early_media;
}
......@@ -1062,33 +1095,46 @@ void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int
cp->audio_bw=bandwidth;
}
#ifdef VIDEO_ENABLED
/**
* Request remote side to send us a Video Fast Update.
**/
void linphone_call_send_vfu_request(LinphoneCall *call)
{
if (LinphoneCallStreamsRunning == linphone_call_get_state(call))
sal_call_send_vfu_request(call->op);
void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value){
params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value);
}
const char *linphone_call_params_get_custom_header(LinphoneCallParams *params, const char *header_name){
return sal_custom_header_find(params->custom_headers,header_name);
}
void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParams *cp){
memcpy(ncp,cp,sizeof(LinphoneCallParams));
if (cp->record_file) ncp->record_file=ms_strdup(cp->record_file);
/*
* The management of the custom headers is not optimal. We copy everything while ref counting would be more efficient.
*/
if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers);
}
#endif
/**
*
* Copy existing LinphoneCallParams to a new LinphoneCallParams object.
**/
LinphoneCallParams * linphone_call_params_copy(const LinphoneCallParams *cp){
LinphoneCallParams *ncp=ms_new0(LinphoneCallParams,1);
memcpy(ncp,cp,sizeof(LinphoneCallParams));
_linphone_call_params_copy(ncp,cp);
return ncp;
}
void linphone_call_params_uninit(LinphoneCallParams *p){
if (p->record_file) ms_free(p->record_file);
if (p->custom_headers) sal_custom_header_free(p->custom_headers);
}
/**
*
* Destroy LinphoneCallParams.
**/
void linphone_call_params_destroy(LinphoneCallParams *p){
linphone_call_params_uninit(p);
ms_free(p);
}
/**
* @}
**/
......@@ -1329,10 +1375,10 @@ static void post_configure_audio_streams(LinphoneCall*call){
LinphoneCore *lc=call->core;
_post_configure_audio_stream(st,lc,call->audio_muted);
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);*/
}
if (call->record_active)
linphone_call_start_recording(call);
}
static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){
......@@ -1484,6 +1530,8 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
if (captcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(captcard, stream->max_rate);
audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc);
audio_stream_enable_adaptive_jittcomp(call->audiostream, linphone_core_audio_adaptive_jittcomp_enabled(lc));
if (!call->params.in_conference && call->params.record_file)
audio_stream_mixed_record_open(call->audiostream,call->params.record_file);
audio_stream_start_full(
call->audiostream,
call->audio_profile,
......@@ -1512,23 +1560,23 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
}
audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
/* valid local tags are > 0 */
/* valid local tags are > 0 */
if (stream->proto == SalProtoRtpSavp) {
const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
SalProtoRtpSavp,SalAudio);
int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
if (crypto_idx >= 0) {
audio_stream_enable_srtp(
call->audiostream,
stream->crypto[0].algo,
local_st_desc->crypto[crypto_idx].master_key,
stream->crypto[0].master_key);
call->audiostream_encrypted=TRUE;
} else {
ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
call->audiostream_encrypted=FALSE;
}
const SalStreamDescription *local_st_desc=sal_media_description_find_stream(call->localdesc,
SalProtoRtpSavp,SalAudio);
int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag);
if (crypto_idx >= 0) {
audio_stream_enable_srtp(
call->audiostream,
stream->crypto[0].algo,
local_st_desc->crypto[crypto_idx].master_key,
stream->crypto[0].master_key);
call->audiostream_encrypted=TRUE;
} else {
ms_warning("Failed to find local crypto algo with tag: %d", stream->crypto_local_tag);
call->audiostream_encrypted=FALSE;
}
}else call->audiostream_encrypted=FALSE;
if (call->params.in_conference){
/*transform the graph to connect it to the conference filter */
......@@ -1981,6 +2029,53 @@ const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call)
return &call->stats[LINPHONE_CALL_STATS_VIDEO];
}
/**