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; const char *statestr=lp_config_get_string(lc->config,"sound","ec_state",NULL); 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); if (statestr && audiostream->ec){ ms_filter_call_method(audiostream->ec,MS_ECHO_CANCELLER_SET_STATE_STRING,(void*)statestr); } } 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); call->audiostream_app_evq = ortp_ev_queue_new(); rtp_session_register_event_queue(audiostream->session,call->audiostream_app_evq); #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)); 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->v_rtp) rtp_session_set_transports(call->videostream->session,lc->v_rtp,lc->v_rtcp); 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 } #else call->videostream=NULL; #endif }
int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char *rem_rtp_ip,int rem_rtp_port, const char *rem_rtcp_ip, int rem_rtcp_port, int payload,int jitt_comp, const char *infile, const char *outfile, MSSndCard *playcard, MSSndCard *captcard, bool_t use_ec) { RtpSession *rtps=stream->ms.session; PayloadType *pt,*tel_ev; int tmp; MSConnectionHelper h; int sample_rate; MSRtpPayloadPickerContext picker_context; bool_t has_builtin_ec=FALSE; rtp_session_set_profile(rtps,profile); if (rem_rtp_port>0) rtp_session_set_remote_addr_full(rtps,rem_rtp_ip,rem_rtp_port,rem_rtcp_ip,rem_rtcp_port); if (rem_rtcp_port<=0){ rtp_session_enable_rtcp(rtps,FALSE); } rtp_session_set_payload_type(rtps,payload); rtp_session_set_jitter_compensation(rtps,jitt_comp); if (rem_rtp_port>0) ms_filter_call_method(stream->ms.rtpsend,MS_RTP_SEND_SET_SESSION,rtps); stream->ms.rtprecv=ms_filter_new(MS_RTP_RECV_ID); ms_filter_call_method(stream->ms.rtprecv,MS_RTP_RECV_SET_SESSION,rtps); stream->ms.session=rtps; if((stream->features & AUDIO_STREAM_FEATURE_DTMF) != 0) stream->dtmfgen=ms_filter_new(MS_DTMF_GEN_ID); else stream->dtmfgen=NULL; rtp_session_signal_connect(rtps,"telephone-event",(RtpCallback)on_dtmf_received,(unsigned long)stream); rtp_session_signal_connect(rtps,"payload_type_changed",(RtpCallback)mediastream_payload_type_changed,(unsigned long)&stream->ms); /* creates the local part */ if (captcard!=NULL){ if (stream->soundread==NULL) stream->soundread=ms_snd_card_create_reader(captcard); has_builtin_ec=!!(ms_snd_card_get_capabilities(captcard) & MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER); }else { stream->soundread=ms_filter_new(MS_FILE_PLAYER_ID); stream->read_resampler=ms_filter_new(MS_RESAMPLE_ID); if (infile!=NULL) audio_stream_play(stream,infile); } if (playcard!=NULL) { if (stream->soundwrite==NULL) stream->soundwrite=ms_snd_card_create_writer(playcard); }else { stream->soundwrite=ms_filter_new(MS_FILE_REC_ID); if (outfile!=NULL) audio_stream_record(stream,outfile); } /* creates the couple of encoder/decoder */ pt=rtp_profile_get_payload(profile,payload); if (pt==NULL){ ms_error("audiostream.c: undefined payload type."); return -1; } tel_ev=rtp_profile_get_payload_from_mime (profile,"telephone-event"); if ((stream->features & AUDIO_STREAM_FEATURE_DTMF_ECHO) != 0 && (tel_ev==NULL || ( (tel_ev->flags & PAYLOAD_TYPE_FLAG_CAN_RECV) && !(tel_ev->flags & PAYLOAD_TYPE_FLAG_CAN_SEND))) && ( strcasecmp(pt->mime_type,"pcmu")==0 || strcasecmp(pt->mime_type,"pcma")==0)){ /*if no telephone-event payload is usable and pcma or pcmu is used, we will generate inband dtmf*/ stream->dtmfgen_rtp=ms_filter_new (MS_DTMF_GEN_ID); } else { stream->dtmfgen_rtp=NULL; } if (ms_filter_call_method(stream->ms.rtpsend,MS_FILTER_GET_SAMPLE_RATE,&sample_rate)!=0){ ms_error("Sample rate is unknown for RTP side !"); return -1; } stream->ms.encoder=ms_filter_create_encoder(pt->mime_type); stream->ms.decoder=ms_filter_create_decoder(pt->mime_type); if ((stream->ms.encoder==NULL) || (stream->ms.decoder==NULL)){ /* big problem: we have not a registered codec for this payload...*/ ms_error("audio_stream_start_full: No decoder or encoder available for payload %s.",pt->mime_type); return -1; } if (ms_filter_has_method(stream->ms.decoder, MS_FILTER_SET_RTP_PAYLOAD_PICKER)) { ms_message(" decoder has FEC capabilities"); picker_context.filter_graph_manager=stream; picker_context.picker=&audio_stream_payload_picker; ms_filter_call_method(stream->ms.decoder,MS_FILTER_SET_RTP_PAYLOAD_PICKER, &picker_context); } if((stream->features & AUDIO_STREAM_FEATURE_VOL_SND) != 0) stream->volsend=ms_filter_new(MS_VOLUME_ID); else stream->volsend=NULL; if((stream->features & AUDIO_STREAM_FEATURE_VOL_RCV) != 0) stream->volrecv=ms_filter_new(MS_VOLUME_ID); else stream->volrecv=NULL; audio_stream_enable_echo_limiter(stream,stream->el_type); audio_stream_enable_noise_gate(stream,stream->use_ng); if (stream->use_agc){ int tmp=1; if (stream->volsend==NULL) stream->volsend=ms_filter_new(MS_VOLUME_ID); ms_filter_call_method(stream->volsend,MS_VOLUME_ENABLE_AGC,&tmp); } if (stream->dtmfgen) { ms_filter_call_method(stream->dtmfgen,MS_FILTER_SET_SAMPLE_RATE,&sample_rate); ms_filter_call_method(stream->dtmfgen,MS_FILTER_SET_NCHANNELS,&pt->channels); } if (stream->dtmfgen_rtp) { ms_filter_call_method(stream->dtmfgen_rtp,MS_FILTER_SET_SAMPLE_RATE,&sample_rate); ms_filter_call_method(stream->dtmfgen_rtp,MS_FILTER_SET_NCHANNELS,&pt->channels); } /* give the sound filters some properties */ if (ms_filter_call_method(stream->soundread,MS_FILTER_SET_SAMPLE_RATE,&sample_rate) != 0) { /* need to add resampler*/ if (stream->read_resampler == NULL) stream->read_resampler=ms_filter_new(MS_RESAMPLE_ID); } ms_filter_call_method(stream->soundread,MS_FILTER_SET_NCHANNELS,&pt->channels); if (ms_filter_call_method(stream->soundwrite,MS_FILTER_SET_SAMPLE_RATE,&sample_rate) != 0) { /* need to add resampler*/ if (stream->write_resampler == NULL) stream->write_resampler=ms_filter_new(MS_RESAMPLE_ID); } ms_filter_call_method(stream->soundwrite,MS_FILTER_SET_NCHANNELS,&pt->channels); // Override feature if ( ((stream->features & AUDIO_STREAM_FEATURE_EC) && !use_ec) || has_builtin_ec ) stream->features &=~AUDIO_STREAM_FEATURE_EC; /*configure the echo canceller if required */ if ((stream->features & AUDIO_STREAM_FEATURE_EC) == 0 && stream->ec != NULL) { ms_filter_destroy(stream->ec); stream->ec=NULL; } if (stream->ec){ if (!stream->is_ec_delay_set){ int delay_ms=ms_snd_card_get_minimal_latency(captcard); if (delay_ms!=0){ ms_message("Setting echo canceller delay with value provided by soundcard: %i ms",delay_ms); ms_filter_call_method(stream->ec,MS_ECHO_CANCELLER_SET_DELAY,&delay_ms); } } ms_filter_call_method(stream->ec,MS_FILTER_SET_SAMPLE_RATE,&sample_rate); } if (stream->features & AUDIO_STREAM_FEATURE_MIXED_RECORDING){ int val=0; int pin=1; stream->recorder=ms_filter_new(MS_FILE_REC_ID); stream->recorder_mixer=ms_filter_new(MS_AUDIO_MIXER_ID); stream->recv_tee=ms_filter_new(MS_TEE_ID); stream->send_tee=ms_filter_new(MS_TEE_ID); ms_filter_call_method(stream->recorder_mixer,MS_AUDIO_MIXER_ENABLE_CONFERENCE_MODE,&val); ms_filter_call_method(stream->recorder_mixer,MS_FILTER_SET_SAMPLE_RATE,&sample_rate); ms_filter_call_method(stream->recorder_mixer,MS_FILTER_SET_NCHANNELS,&pt->channels); ms_filter_call_method(stream->recv_tee,MS_TEE_MUTE,&pin); ms_filter_call_method(stream->send_tee,MS_TEE_MUTE,&pin); ms_filter_call_method(stream->recorder,MS_FILTER_SET_SAMPLE_RATE,&sample_rate); ms_filter_call_method(stream->recorder,MS_FILTER_SET_NCHANNELS,&pt->channels); } /* give the encoder/decoder some parameters*/ ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_SAMPLE_RATE,&sample_rate); ms_message("Payload's bitrate is %i",pt->normal_bitrate); if (pt->normal_bitrate>0){ ms_message("Setting audio encoder network bitrate to %i",pt->normal_bitrate); ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_BITRATE,&pt->normal_bitrate); } ms_filter_call_method(stream->ms.encoder,MS_FILTER_SET_NCHANNELS,&pt->channels); ms_filter_call_method(stream->ms.decoder,MS_FILTER_SET_SAMPLE_RATE,&sample_rate); ms_filter_call_method(stream->ms.decoder,MS_FILTER_SET_NCHANNELS,&pt->channels); if (pt->send_fmtp!=NULL) { char value[16]={0}; int ptime; if (ms_filter_has_method(stream->ms.encoder,MS_AUDIO_ENCODER_SET_PTIME)){ if (fmtp_get_value(pt->send_fmtp,"ptime",value,sizeof(value)-1)){ ptime=atoi(value); ms_filter_call_method(stream->ms.encoder,MS_AUDIO_ENCODER_SET_PTIME,&ptime); } } ms_filter_call_method(stream->ms.encoder,MS_FILTER_ADD_FMTP, (void*)pt->send_fmtp); } if (pt->recv_fmtp!=NULL) ms_filter_call_method(stream->ms.decoder,MS_FILTER_ADD_FMTP,(void*)pt->recv_fmtp); /*create the equalizer*/ if ((stream->features & AUDIO_STREAM_FEATURE_EQUALIZER) != 0){ stream->equalizer=ms_filter_new(MS_EQUALIZER_ID); if(stream->equalizer) { tmp=stream->eq_active; ms_filter_call_method(stream->equalizer,MS_EQUALIZER_SET_ACTIVE,&tmp); } }else stream->equalizer=NULL; /*configure resampler if needed*/ ms_filter_call_method(stream->ms.rtpsend, MS_FILTER_SET_NCHANNELS, &pt->channels); ms_filter_call_method(stream->ms.rtprecv, MS_FILTER_SET_NCHANNELS, &pt->channels); if (stream->read_resampler){ audio_stream_configure_resampler(stream->read_resampler,stream->soundread,stream->ms.rtpsend); } if (stream->write_resampler){ audio_stream_configure_resampler(stream->write_resampler,stream->ms.rtprecv,stream->soundwrite); } if (stream->ms.use_rc){ stream->ms.rc=ms_audio_bitrate_controller_new(stream->ms.session,stream->ms.encoder,0); } /* Create PLC */ if ((stream->features & AUDIO_STREAM_FEATURE_PLC) != 0) { int decoder_have_plc = 0; if (ms_filter_has_method(stream->ms.decoder, MS_AUDIO_DECODER_HAVE_PLC)) { if (ms_filter_call_method(stream->ms.decoder, MS_AUDIO_DECODER_HAVE_PLC, &decoder_have_plc) != 0) { ms_warning("MS_AUDIO_DECODER_HAVE_PLC function error: enable default plc"); } } else { ms_warning("MS_DECODER_HAVE_PLC function not implemented by the decoder: enable default plc"); } if (decoder_have_plc == 0) { stream->plc = ms_filter_new(MS_GENERIC_PLC_ID); } if (stream->plc) { ms_filter_call_method(stream->plc, MS_FILTER_SET_NCHANNELS, &pt->channels); ms_filter_call_method(stream->plc, MS_FILTER_SET_SAMPLE_RATE, &sample_rate); } } else { stream->plc = NULL; } /* create ticker */ if (stream->ms.ticker==NULL) start_ticker(&stream->ms); else{ /*we were using the dummy preload graph, destroy it*/ if (stream->dummy) stop_preload_graph(stream); } /* and then connect all */ /* tip: draw yourself the picture if you don't understand */ /*sending graph*/ ms_connection_helper_start(&h); ms_connection_helper_link(&h,stream->soundread,-1,0); if (stream->read_resampler) ms_connection_helper_link(&h,stream->read_resampler,0,0); if (stream->ec) ms_connection_helper_link(&h,stream->ec,1,1); if (stream->volsend) ms_connection_helper_link(&h,stream->volsend,0,0); if (stream->dtmfgen_rtp) ms_connection_helper_link(&h,stream->dtmfgen_rtp,0,0); if (stream->send_tee) ms_connection_helper_link(&h,stream->send_tee,0,0); ms_connection_helper_link(&h,stream->ms.encoder,0,0); ms_connection_helper_link(&h,stream->ms.rtpsend,0,-1); /*receiving graph*/ ms_connection_helper_start(&h); ms_connection_helper_link(&h,stream->ms.rtprecv,-1,0); ms_connection_helper_link(&h,stream->ms.decoder,0,0); if (stream->plc) ms_connection_helper_link(&h,stream->plc,0,0); if (stream->dtmfgen) ms_connection_helper_link(&h,stream->dtmfgen,0,0); if (stream->volrecv) ms_connection_helper_link(&h,stream->volrecv,0,0); if (stream->recv_tee) ms_connection_helper_link(&h,stream->recv_tee,0,0); if (stream->equalizer) ms_connection_helper_link(&h,stream->equalizer,0,0); if (stream->ec) ms_connection_helper_link(&h,stream->ec,0,0); if (stream->write_resampler) ms_connection_helper_link(&h,stream->write_resampler,0,0); ms_connection_helper_link(&h,stream->soundwrite,0,-1); /*call recording part, attached to both outgoing and incoming graphs*/ if (stream->recorder){ ms_filter_link(stream->send_tee,1,stream->recorder_mixer,0); ms_filter_link(stream->recv_tee,1,stream->recorder_mixer,1); ms_filter_link(stream->recorder_mixer,0,stream->recorder,0); } /*to make sure all preprocess are done before befre processing audio*/ ms_ticker_attach_multiple(stream->ms.ticker ,stream->soundread ,stream->ms.rtprecv ,NULL); stream->ms.start_time=ms_time(NULL); stream->ms.is_beginning=TRUE; return 0; }
static void run_media_streams(int localport, const char *remote_ip, int remoteport, int payload, const char *fmtp, int jitter, int bitrate, MSVideoSize vs, bool_t ec, bool_t agc, bool_t eq) { AudioStream *audio=NULL; #ifdef VIDEO_ENABLED VideoStream *video=NULL; #endif RtpSession *session=NULL; PayloadType *pt; RtpProfile *profile=rtp_profile_clone_full(&av_profile); OrtpEvQueue *q=ortp_ev_queue_new(); ms_init(); signal(SIGINT,stop_handler); pt=rtp_profile_get_payload(profile,payload); if (pt==NULL){ printf("Error: no payload defined with number %i.",payload); exit(-1); } if (fmtp!=NULL) payload_type_set_send_fmtp(pt,fmtp); if (bitrate>0) pt->normal_bitrate=bitrate; if (pt->type!=PAYLOAD_VIDEO){ MSSndCardManager *manager=ms_snd_card_manager_get(); MSSndCard *capt= capture_card==NULL ? ms_snd_card_manager_get_default_capture_card(manager) : ms_snd_card_manager_get_card(manager,capture_card); MSSndCard *play= playback_card==NULL ? ms_snd_card_manager_get_default_playback_card(manager) : ms_snd_card_manager_get_card(manager,playback_card); audio=audio_stream_new(localport,ms_is_ipv6(remote_ip)); audio_stream_enable_automatic_gain_control(audio,agc); audio_stream_enable_noise_gate(audio,use_ng); audio_stream_set_echo_canceller_params(audio,ec_len_ms,ec_delay_ms,ec_framesize); printf("Starting audio stream.\n"); audio_stream_start_full(audio,profile,remote_ip,remoteport,remoteport+1, payload, jitter,infile,outfile, outfile==NULL ? play : NULL ,infile==NULL ? capt : NULL,infile!=NULL ? FALSE: ec); if (audio) { if (use_ng && ng_threshold!=-1) ms_filter_call_method(audio->volsend,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_threshold); session=audio->session; } }else{ #ifdef VIDEO_ENABLED if (eq){ ms_fatal("Cannot put an audio equalizer in a video stream !"); exit(-1); } printf("Starting video stream.\n"); video=video_stream_new(localport, ms_is_ipv6(remote_ip)); video_stream_set_sent_video_size(video,vs); video_stream_use_preview_video_window(video,two_windows); video_stream_start(video,profile, remote_ip, remoteport,remoteport+1, payload, jitter, ms_web_cam_manager_get_default_cam(ms_web_cam_manager_get())); session=video->session; #else printf("Error: video support not compiled.\n"); #endif } if (eq || ec){ /*read from stdin interactive commands */ char commands[128]; commands[127]='\0'; ms_sleep(1); /* ensure following text be printed after ortp messages */ if (eq) printf("\nPlease enter equalizer requests, such as 'eq active 1', 'eq active 0', 'eq 1200 0.1 200'\n"); if (ec) printf("\nPlease enter echo canceller requests: ec reset; ec <delay ms> <tail_length ms'\n"); while(fgets(commands,sizeof(commands)-1,stdin)!=NULL){ int active,freq,freq_width; int delay_ms, tail_ms; float gain; if (sscanf(commands,"eq active %i",&active)==1){ audio_stream_enable_equalizer(audio,active); printf("OK\n"); }else if (sscanf(commands,"eq %i %f %i",&freq,&gain,&freq_width)==3){ audio_stream_equalizer_set_gain(audio,freq,gain,freq_width); printf("OK\n"); }else if (sscanf(commands,"eq %i %f",&freq,&gain)==2){ audio_stream_equalizer_set_gain(audio,freq,gain,0); printf("OK\n"); }else if (strstr(commands,"dump")){ int n=0,i; float *t; ms_filter_call_method(audio->equalizer,MS_EQUALIZER_GET_NUM_FREQUENCIES,&n); t=(float*)alloca(sizeof(float)*n); ms_filter_call_method(audio->equalizer,MS_EQUALIZER_DUMP_STATE,t); for(i=0;i<n;++i){ if (fabs(t[i]-1)>0.01){ printf("%i:%f:0 ",(i*pt->clock_rate)/(2*n),t[i]); } } printf("\nOK\n"); }else if (sscanf(commands,"ec reset %i",&active)==1){ //audio_stream_enable_equalizer(audio,active); //printf("OK\n"); }else if (sscanf(commands,"ec active %i",&active)==1){ //audio_stream_enable_equalizer(audio,active); //printf("OK\n"); }else if (sscanf(commands,"ec %i %i",&delay_ms,&tail_ms)==2){ audio_stream_set_echo_canceller_params(audio,tail_ms,delay_ms,128); // revisit: workaround with old method call to force echo reset delay_ms*=8; ms_filter_call_method(audio->ec,MS_FILTER_SET_PLAYBACKDELAY,&delay_ms); printf("OK\n"); }else if (strstr(commands,"quit")){ break; }else printf("Cannot understand this.\n"); } }else{ /* no interactive stuff - continuous debug output */ rtp_session_register_event_queue(session,q); while(cond) { int n; for(n=0;n<100;++n){ #ifdef WIN32 MSG msg; Sleep(10); while (PeekMessage(&msg, NULL, 0, 0,1)){ TranslateMessage(&msg); DispatchMessage(&msg); } #else struct timespec ts; ts.tv_sec=0; ts.tv_nsec=10000000; nanosleep(&ts,NULL); #endif #if defined(VIDEO_ENABLED) if (video) video_stream_iterate(video); #endif } ortp_global_stats_display(); if (session){ printf("Bandwidth usage: download=%f kbits/sec, upload=%f kbits/sec\n", rtp_session_compute_recv_bandwidth(session)*1e-3, rtp_session_compute_send_bandwidth(session)*1e-3); parse_events(q); } } } printf("stopping all...\n"); if (audio) audio_stream_stop(audio); #ifdef VIDEO_ENABLED if (video) video_stream_stop(video); #endif ortp_ev_queue_destroy(q); rtp_profile_destroy(profile); }