/** * Returns a media description to run the streams with, based on a local offer * and the returned response (remote). **/ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, const SalMediaDescription *remote_answer, SalMediaDescription *result) { int i,j; const SalStreamDescription *ls,*rs; for(i=0,j=0; i<local_offer->nb_streams; ++i) { ms_message("Processing for stream %i",i); ls=&local_offer->streams[i]; rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type); if (rs) { initiate_outgoing(ls,rs,&result->streams[j]); memcpy(&result->streams[i].rtcp_xr, &ls->rtcp_xr, sizeof(result->streams[i].rtcp_xr)); if ((ls->rtcp_xr.enabled == TRUE) && (rs->rtcp_xr.enabled == FALSE)) { result->streams[i].rtcp_xr.enabled = FALSE; } ++j; } else ms_warning("No matching stream for %i",i); } result->nb_streams=local_offer->nb_streams; result->bandwidth=remote_answer->bandwidth; strcpy(result->addr,remote_answer->addr); memcpy(&result->rtcp_xr, &local_offer->rtcp_xr, sizeof(result->rtcp_xr)); if ((local_offer->rtcp_xr.enabled == TRUE) && (remote_answer->rtcp_xr.enabled == FALSE)) { result->rtcp_xr.enabled = FALSE; } return 0; }
/** * Returns a media description to run the streams with, based on the local capabilities and * and the received offer. * The returned media description is an answer and should be sent to the offerer. **/ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities, const SalMediaDescription *remote_offer, SalMediaDescription *result, bool_t one_matching_codec) { int i; const SalStreamDescription *ls,*rs; for(i=0; i<remote_offer->nstreams; ++i) { rs=&remote_offer->streams[i]; ms_message("Processing for stream %i",i); ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type); if (ls) { initiate_incoming(ls,rs,&result->streams[i],one_matching_codec); } else { /* create an inactive stream for the answer, as there where no matching stream a local capability */ result->streams[i].dir=SalStreamInactive; result->streams[i].port=0; result->streams[i].type=rs->type; if (rs->type==SalOther) { strncpy(result->streams[i].typeother,rs->typeother,sizeof(rs->typeother)-1); } } } result->nstreams=i; strcpy(result->username, local_capabilities->username); strcpy(result->addr,local_capabilities->addr); result->bandwidth=local_capabilities->bandwidth; result->session_ver=local_capabilities->session_ver; result->session_id=local_capabilities->session_id; return 0; }
SalStreamDescription * sal_media_description_find_best_stream(SalMediaDescription *md, SalStreamType type) { SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoUdpTlsRtpSavpf, type); if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoUdpTlsRtpSavp, type); if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type); if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type); if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvpf, type); if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvp, type); return desc; }
/** * Returns a media description to run the streams with, based on the local capabilities and * and the received offer. * The returned media description is an answer and should be sent to the offerer. **/ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities, const SalMediaDescription *remote_offer, SalMediaDescription *result, bool_t one_matching_codec){ int i; const SalStreamDescription *ls=NULL,*rs; for(i=0;i<remote_offer->nstreams;++i){ rs=&remote_offer->streams[i]; if (rs->proto!=SalProtoUnknown){ ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,rs->proto,rs->type); /* if matching failed, and remote proposes Avp only, ask for local Savp streams */ if (!ls && rs->proto == SalProtoRtpAvp) { ls=sal_media_description_find_stream((SalMediaDescription*)local_capabilities,SalProtoRtpSavp,rs->type); } }else ms_warning("Unknown protocol for mline %i, declining",i); if (ls){ initiate_incoming(ls,rs,&result->streams[i],one_matching_codec); } else { /* create an inactive stream for the answer, as there where no matching stream a local capability */ result->streams[i].dir=SalStreamInactive; result->streams[i].port=0; result->streams[i].type=rs->type; result->streams[i].proto=rs->proto; if (rs->type==SalOther){ strncpy(result->streams[i].typeother,rs->typeother,sizeof(rs->typeother)-1); } } } result->nstreams=i; strcpy(result->username, local_capabilities->username); strcpy(result->addr,local_capabilities->addr); result->bandwidth=local_capabilities->bandwidth; result->session_ver=local_capabilities->session_ver; result->session_id=local_capabilities->session_id; return 0; }
/** * Returns a media description to run the streams with, based on a local offer * and the returned response (remote). **/ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, const SalMediaDescription *remote_answer, SalMediaDescription *result) { int i,j; const SalStreamDescription *ls,*rs; for(i=0,j=0; i<local_offer->nstreams; ++i) { ms_message("Processing for stream %i",i); ls=&local_offer->streams[i]; rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type); if (rs) { initiate_outgoing(ls,rs,&result->streams[j]); ++j; } else ms_warning("No matching stream for %i",i); } result->nstreams=j; result->bandwidth=remote_answer->bandwidth; strcpy(result->addr,remote_answer->addr); return 0; }
SalStreamDescription * sal_media_description_find_secure_stream_of_type(SalMediaDescription *md, SalStreamType type) { SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type); if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type); return desc; }
void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone){ 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; #ifdef VIDEO_ENABLED const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc, SalProtoRtpAvp,SalVideo); #endif bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc); if(call->audiostream == NULL) { ms_fatal("start_media_stream() called without prior init !"); return; } call->current_params = call->params; /* 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 && stream->dir!=SalStreamInactive && stream->port!=0){ 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(call,call->resultdesc,stream,&used_pt); bool_t use_ec,use_arc_audio=use_arc; if (used_pt!=-1){ if (playcard==NULL) { ms_warning("No card defined for playback !"); } if (captcard==NULL) { ms_warning("No card defined for capture !"); } /*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; /*And we will eventually play "playfile" if set by the user*/ /*playfile=NULL;*/ } if (send_ringbacktone){ captcard=NULL; playfile=NULL;/* it is setup later*/ } /*if playfile are supplied don't use soundcards*/ if (lc->use_files) { captcard=NULL; playcard=NULL; } use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc); #if defined(VIDEO_ENABLED) if (vstream && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){ /*when video is used, do not make adaptive rate control on audio, it is stupid.*/ use_arc_audio=FALSE; #if defined(ANDROID) /*On android we have to disable the echo canceller to preserve CPU for video codecs */ use_ec=FALSE; #endif } #endif audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc_audio); 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, use_ec ); post_configure_audio_streams(call); if (all_inputs_muted && !send_ringbacktone){ audio_stream_set_mic_gain(call->audiostream,0); } if (stream->dir==SalStreamSendOnly && playfile!=NULL){ int pause_time=500; ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time); } if (send_ringbacktone){ setup_ring_player(lc,call); } audio_stream_set_rtcp_information(call->audiostream, cname, tool); }else ms_warning("No audio stream accepted ?"); } } #ifdef VIDEO_ENABLED { used_pt=-1; /* shutdown preview */ if (lc->previewstream!=NULL) { video_preview_stop(lc->previewstream); lc->previewstream=NULL; } call->current_params.has_video=FALSE; if (vstream && vstream->dir!=SalStreamInactive && vstream->port!=0) { const char *addr=vstream->addr[0]!='\0' ? vstream->addr : call->resultdesc->addr; call->video_profile=make_profile(call,call->resultdesc,vstream,&used_pt); if (used_pt!=-1){ VideoStreamDir dir=VideoStreamSendRecv; MSWebCam *cam=lc->video_conf.device; bool_t is_inactive=FALSE; call->current_params.has_video=TRUE; 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 (lc->video_window_id!=0) video_stream_set_native_window_id(call->videostream,lc->video_window_id); if (lc->preview_window_id!=0) video_stream_set_native_preview_window_id (call->videostream,lc->preview_window_id); video_stream_use_preview_video_window (call->videostream,lc->use_preview_window); if (vstream->dir==SalStreamSendOnly && lc->video_conf.capture ){ cam=get_nowebcam_device(); dir=VideoStreamSendOnly; }else if (vstream->dir==SalStreamRecvOnly && lc->video_conf.display ){ dir=VideoStreamRecvOnly; }else if (vstream->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 (call->camera_active==FALSE || all_inputs_muted){ cam=get_nowebcam_device(); } if (!is_inactive){ video_stream_set_direction (call->videostream, dir); video_stream_start(call->videostream, call->video_profile, addr, vstream->port, vstream->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 call->all_muted=all_inputs_muted; call->playing_ringbacktone=send_ringbacktone; call->up_bw=linphone_core_get_upload_bandwidth(lc); if (ortp_zrtp_available()) { OrtpZrtpParams params; params.zid=get_hexa_zrtp_identifier(lc); params.zid_file=lc->zrtp_secrets_cache; audio_stream_enable_zrtp(call->audiostream,¶ms); } goto end; end: ms_free(cname); linphone_address_destroy(me); }