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;
+ if (call->localdesc->streams[0].max_rate>0) ms_snd_card_set_preferred_sample_rate(ringcard, call->localdesc->streams[0].max_rate);
lc->ringstream=ring_start(lc->sound_conf.remote_ring,2000,ringcard);
}
ms_message("Remote ringing...");
call->state==LinphoneCallOutgoingRinging ||
call->state==LinphoneCallOutgoingEarlyMedia){
linphone_call_set_state(call,LinphoneCallConnected,"Connected");
+ if (call->referer) linphone_core_notify_refer_state(lc,call->referer,call);
}
if (md && !sal_media_description_empty(md)){
if (sal_media_description_has_dir(md,SalStreamSendOnly) ||
}
}
linphone_core_update_streams (lc,call,md);
- linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running");
if (!call->current_params.in_conference)
lc->current_call=call;
+ linphone_call_set_state(call, LinphoneCallStreamsRunning, "Streams running");
}
}else{
/*send a bye*/
} else {
linphone_call_set_state(call,LinphoneCallError,msg);
}
+ if (call->referer && linphone_call_get_state(call->referer)==LinphoneCallPaused && call->referer->was_automatically_paused){
+ /*resume to the call that send us the refer automatically*/
+ linphone_core_resume_call(lc,call->referer);
+ }
}
static void call_released(SalOp *op){
if (call->state!=LinphoneCallPaused){
ms_message("Automatically pausing current call to accept transfer.");
linphone_core_pause_call(lc,call);
+ call->was_automatically_paused=TRUE;
}
linphone_core_start_refered_call(lc,call);
- sal_call_accept_refer(op);
}else if (lc->vtable.refer_received){
lc->vtable.refer_received(lc,referto);
- sal_call_accept_refer(op);
}
}
lc->vtable.notify_recv(lc,call,from,msg);
}
-static void notify_presence(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg){
+static void notify_presence(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg){
LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
linphone_notify_recv(lc,op,ss,status);
}
}
}
+static void notify_refer(SalOp *op, SalReferStatus status){
+ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op));
+ LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op);
+ LinphoneCallState cstate;
+ if (call==NULL) {
+ ms_warning("Receiving notify_refer for unknown call.");
+ return ;
+ }
+ switch(status){
+ case SalReferTrying:
+ cstate=LinphoneCallOutgoingProgress;
+ break;
+ case SalReferSuccess:
+ cstate=LinphoneCallConnected;
+ break;
+ case SalReferFailed:
+ cstate=LinphoneCallError;
+ break;
+ default:
+ cstate=LinphoneCallError;
+ }
+ if (lc->vtable.transfer_state_changed)
+ lc->vtable.transfer_state_changed(lc,call,cstate);
+ if (cstate==LinphoneCallConnected){
+ /*automatically terminate the call as the transfer is complete.*/
+ linphone_core_terminate_call(lc,call);
+ }
+}
+
SalCallbacks linphone_sal_callbacks={
call_received,
call_ringing,
text_received,
notify,
notify_presence,
+ notify_refer,
subscribe_received,
subscribe_closed,
ping_reply
#include "mediastreamer2/msfileplayer.h"
#include "mediastreamer2/msjpegwriter.h"
#include "mediastreamer2/mseventqueue.h"
+ #include "mediastreamer2/mssndcard.h"
#ifdef VIDEO_ENABLED
static MSWebCam *get_nowebcam_device(){
propagate_encryption_changed(call);
}
- static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit){
+ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate){
MSList *l=NULL;
const MSList *it;
+ if (max_sample_rate) *max_sample_rate=0;
for(it=codecs;it!=NULL;it=it->next){
PayloadType *pt=(PayloadType*)it->data;
if (pt->flags & PAYLOAD_TYPE_ENABLED){
}
if (linphone_core_check_payload_type_usability(lc,pt)){
l=ms_list_append(l,payload_type_clone(pt));
+ if (max_sample_rate && payload_type_get_rate(pt)>*max_sample_rate) *max_sample_rate=payload_type_get_rate(pt);
}
}
}
const char *username=linphone_address_get_username (addr);
SalMediaDescription *md=sal_media_description_new();
+
md->session_id=session_id;
md->session_ver=session_ver;
md->nstreams=1;
SalProtoRtpSavp : 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,call->params.audio_bw);
+ l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate);
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 (call->params.has_video){
md->streams[1].port=call->video_port;
md->streams[1].proto=md->streams[0].proto;
md->streams[1].type=SalVideo;
- l=make_codec_list(lc,lc->codecs_conf.video_codecs,0);
+ l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL);
md->streams[1].payloads=l;
}
discover_mtu(lc,linphone_address_get_domain (to));
if (params->referer){
sal_call_set_referer(call->op,params->referer->op);
+ call->referer=linphone_call_ref(params->referer);
}
return call;
}
linphone_core_stop_dtmf(lc);
call->ringing_beep=FALSE;
}
+ if (call->referer){
+ linphone_call_unref(call->referer);
+ call->referer=NULL;
+ }
}
void linphone_call_fix_call_parameters(LinphoneCall *call){
#ifdef VIDEO_ENABLED
static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){
+ LinphoneCall* call = (LinphoneCall*) user_pointer;
ms_warning("In linphonecall.c: video_stream_event_cb");
switch (event_id) {
case MS_VIDEO_DECODER_DECODING_ERRORS:
ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS");
- linphone_call_send_vfu_request((LinphoneCall*) user_pointer);
+ linphone_call_send_vfu_request(call);
break;
+ case MS_VIDEO_DECODER_FIRST_IMAGE_DECODED:
+ ms_message("First video frame decoded successfully");
+ if (call->nextVideoFrameDecoded._func != NULL)
+ call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data);
+ break;
default:
ms_warning("Unhandled event %i", event_id);
break;
}
#endif
+void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data) {
+ call->nextVideoFrameDecoded._func = cb;
+ call->nextVideoFrameDecoded._user_data = user_data;
+#ifdef VIDEO_ENABLED
+ ms_filter_call_method_noarg(call->videostream->decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
+#endif
+}
+
void linphone_call_init_media_streams(LinphoneCall *call){
LinphoneCore *lc=call->core;
SalMediaDescription *md=call->localdesc;
#ifdef VIDEO_ENABLED
if ((lc->video_conf.display || lc->video_conf.capture) && md->streams[1].port>0){
+ int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
call->videostream=video_stream_new(md->streams[1].port,linphone_core_ipv6_enabled(lc));
- video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
- if( lc->video_conf.displaytype != NULL)
- video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
- video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
- if (lc->rtptf){
- RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
- RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
- rtp_session_set_transports(call->videostream->session,vrtp,vrtcp);
- }
- call->videostream_app_evq = ortp_ev_queue_new();
- rtp_session_register_event_queue(call->videostream->session,call->videostream_app_evq);
+ video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
+ if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->session,video_recv_buf_size);
+
+ if( lc->video_conf.displaytype != NULL)
+ video_stream_set_display_filter_name(call->videostream,lc->video_conf.displaytype);
+ video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
+ if (lc->rtptf){
+ RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
+ RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
+ rtp_session_set_transports(call->videostream->session,vrtp,vrtcp);
+ }
+ call->videostream_app_evq = ortp_ev_queue_new();
+ rtp_session_register_event_queue(call->videostream->session,call->videostream_app_evq);
#ifdef TEST_EXT_RENDERER
video_stream_set_render_callback(call->videostream,rendercb,NULL);
#endif
captcard=playcard=NULL;
}
use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc);
-
+ if (playcard && stream->max_rate>0) ms_snd_card_set_preferred_sample_rate(playcard, stream->max_rate);
+ 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_start_full(
call->audiostream,
cam=get_nowebcam_device();
}
if (!is_inactive){
+ call->log->video_enabled = TRUE;
video_stream_set_direction (call->videostream, dir);
ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
video_stream_set_device_rotation(call->videostream, lc->device_rotation);
SalStreamDir dir;
SalSrtpCryptoAlgo crypto[SAL_CRYPTO_ALGO_MAX];
unsigned int crypto_local_tag;
+ int max_rate;
} SalStreamDescription;
#define SAL_MEDIA_DESCRIPTION_MAX_STREAMS 4
SalPresenceAltService,
}SalPresenceStatus;
-typedef enum SalSubscribeState{
+typedef enum SalReferStatus{
+ SalReferTrying,
+ SalReferSuccess,
+ SalReferFailed
+}SalReferStatus;
+
+typedef enum SalSubscribeStatus{
SalSubscribeActive,
SalSubscribeTerminated
-}SalSubscribeState;
+}SalSubscribeStatus;
typedef void (*SalOnCallReceived)(SalOp *op);
typedef void (*SalOnCallRinging)(SalOp *op);
typedef void (*SalOnDtmfReceived)(SalOp *op, char dtmf);
typedef void (*SalOnRefer)(Sal *sal, SalOp *op, const char *referto);
typedef void (*SalOnTextReceived)(Sal *sal, const char *from, const char *msg);
-typedef void (*SalOnNotify)(SalOp *op, const char *from, const char *value);
-typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeState ss, SalPresenceStatus status, const char *msg);
+typedef void (*SalOnNotify)(SalOp *op, const char *from, const char *event);
+typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state);
+typedef void (*SalOnNotifyPresence)(SalOp *op, SalSubscribeStatus ss, SalPresenceStatus status, const char *msg);
typedef void (*SalOnSubscribeReceived)(SalOp *salop, const char *from);
typedef void (*SalOnSubscribeClosed)(SalOp *salop, const char *from);
typedef void (*SalOnPingReply)(SalOp *salop);
SalOnTextReceived text_received;
SalOnNotify notify;
SalOnNotifyPresence notify_presence;
+ SalOnNotifyRefer notify_refer;
SalOnSubscribeReceived subscribe_received;
SalOnSubscribeClosed subscribe_closed;
SalOnPingReply ping_reply;
bool_t sal_call_autoanswer_asked(SalOp *op);
void sal_call_send_vfu_request(SalOp *h);
int sal_call_is_offerer(const SalOp *h);
+int sal_call_notify_refer_state(SalOp *h, SalOp *newcall);
/*Registration*/
int sal_register(SalOp *op, const char *proxy, const char *from, int expires);