static PayloadType * find_payload_type_best_match(const MSList *l, const PayloadType *refpt){ PayloadType *pt; char value[10]; const MSList *elem; PayloadType *candidate=NULL; for (elem=l;elem!=NULL;elem=elem->next){ pt=(PayloadType*)elem->data; /* 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){ if (pt->recv_fmtp!=NULL && refpt->recv_fmtp!=NULL){ int mode1=0,mode2=0; if (fmtp_get_value(pt->recv_fmtp,"packetization-mode",value,sizeof(value))){ mode1=atoi(value); } if (fmtp_get_value(refpt->recv_fmtp,"packetization-mode",value,sizeof(value))){ mode2=atoi(value); } if (mode1==mode2) break; /*exact match */ } }else break; } } return candidate; }
static PayloadType * amr_match(const MSList *l, const PayloadType *refpt){ PayloadType *pt; char value[10]; const MSList *elem; PayloadType *candidate=NULL; for (elem=l;elem!=NULL;elem=elem->next){ pt=(PayloadType*)elem->data; if ( pt->mime_type && refpt->mime_type && strcasecmp(pt->mime_type, refpt->mime_type)==0 && pt->clock_rate==refpt->clock_rate && pt->channels==refpt->channels) { int octedalign1=0,octedalign2=0; if (pt->recv_fmtp!=NULL && fmtp_get_value(pt->recv_fmtp,"octet-align",value,sizeof(value))){ octedalign1=atoi(value); } if (refpt->send_fmtp!=NULL && fmtp_get_value(refpt->send_fmtp,"octet-align",value,sizeof(value))){ octedalign2=atoi(value); } if (octedalign1==octedalign2) { candidate=pt; break; /*exact match */ } } } return candidate; }
static PayloadType * amr_match(MSOfferAnswerContext *ctx, const MSList *local_payloads, const PayloadType *refpt, const MSList *remote_payloads, bool_t reading_response){ PayloadType *pt; char value[10]; const MSList *elem; PayloadType *candidate=NULL; for (elem=local_payloads;elem!=NULL;elem=elem->next){ pt=(PayloadType*)elem->data; if ( pt->mime_type && refpt->mime_type && strcasecmp(pt->mime_type, refpt->mime_type)==0 && pt->clock_rate==refpt->clock_rate && pt->channels==refpt->channels) { int octedalign1=0,octedalign2=0; if (pt->recv_fmtp!=NULL && fmtp_get_value(pt->recv_fmtp,"octet-align",value,sizeof(value))){ octedalign1=atoi(value); } if (refpt->send_fmtp!=NULL && fmtp_get_value(refpt->send_fmtp,"octet-align",value,sizeof(value))){ octedalign2=atoi(value); } if (octedalign1==octedalign2) { candidate=pt; break; /*exact match */ } } } return candidate ? payload_type_clone(candidate) : NULL; }
static int ms_opus_enc_add_fmtp(MSFilter *f, void *arg) { OpusEncData *d = (OpusEncData *)f->data; const char *fmtp = (const char *)arg; char buf[64]= {0}; if ( fmtp_get_value ( fmtp,"maxplaybackrate",buf,sizeof ( buf ) ) ) { d->maxplaybackrate=atoi(buf); } else if ( fmtp_get_value ( fmtp,"maxptime",buf,sizeof ( buf ) ) ) { d->maxptime=MIN(atoi(buf),120); } else if ( fmtp_get_value ( fmtp,"ptime",buf,sizeof ( buf ) ) ) { int val=atoi(buf); ms_opus_enc_set_ptime(f,&val); } else if ( fmtp_get_value ( fmtp,"minptime",buf,sizeof ( buf ) ) ) { d->minptime=MAX(atoi(buf),20); // minimum shall be 3 but we do not provide less than 20ms ptime. } else if ( fmtp_get_value ( fmtp,"maxaveragebitrate",buf,sizeof ( buf ) ) ) { d->maxaveragebitrate = atoi(buf); } else if ( fmtp_get_value ( fmtp,"stereo",buf,sizeof ( buf ) ) ) { d->stereo = atoi(buf); } else if ( fmtp_get_value ( fmtp,"cbr",buf,sizeof ( buf ) ) ) { if (atoi(buf) == 1 ) { d->vbr = 0; } else { d->vbr = 1; } ms_opus_enc_set_vbr(f); } else if ( fmtp_get_value ( fmtp,"useinbandfec",buf,sizeof ( buf ) ) ) { d->useinbandfec = atoi(buf); } else if ( fmtp_get_value ( fmtp,"usedtx",buf,sizeof ( buf ) ) ) { d->usedtx = atoi(buf); } return 0; }
static int enc_add_fmtp(MSFilter *f, void *arg){ char buf[64]; const char *fmtp=(const char *)arg; SpeexEncState *s=(SpeexEncState*)f->data; memset(buf, '\0', sizeof(buf)); fmtp_get_value(fmtp, "vbr", buf, sizeof(buf)); if (buf[0]=='\0'){ } else if (strstr(buf,"off")!=NULL){ s->vbr=0; } else if (strstr(buf,"on")!=NULL){ s->vbr=1; } else if (strstr(buf,"vad")!=NULL){ s->vbr=2; } memset(buf, '\0', sizeof(buf)); fmtp_get_value(fmtp, "cng", buf, sizeof(buf)); if (buf[0]=='\0'){ } else if (strstr(buf,"off")!=NULL){ s->cng=0; } else if (strstr(buf,"on")!=NULL){ s->cng=1; } memset(buf, '\0', sizeof(buf)); fmtp_get_value(fmtp, "mode", buf, sizeof(buf)); if (buf[0]=='\0' || buf[1]=='\0'){ } else if (buf[0]=='0' || (buf[0]=='"' && buf[1]=='0')){ s->mode=0; } else if (buf[0]=='"' && atoi(buf+1)>=0){ s->mode=atoi(buf+1); } else if (buf[0]!='"' && atoi(buf)>=0){ s->mode=atoi(buf); } else { s->mode = -1; /* default mode */ } memset(buf, '\0', sizeof(buf)); if (fmtp_get_value(fmtp,"ptime",buf,sizeof(buf))){ int val=atoi(buf); enc_set_ptime(f,&val); } return 0; }
void MSOpenH264Encoder::addFmtp(const char *fmtp) { char value[12]; if (fmtp_get_value(fmtp, "packetization-mode", value, sizeof(value))) { mPacketisationMode = atoi(value); ms_message("packetization-mode set to %i", mPacketisationMode); } }
static int dec_add_fmtp(MSFilter *f, void *arg){ DecState *s=(DecState*)f->data; const char *fmtp=(const char *)arg; char buf[32]; if (fmtp_get_value(fmtp, "plc", buf, sizeof(buf))){ s->plc=atoi(buf); } return 0; }
static int enc_add_fmtp(MSFilter *f, void *arg){ EncState *s=(EncState*)f->data; const char *fmtp=(const char *)arg; char tmp[64]; tmp[0] = '\0'; if (fmtp_get_value(fmtp,"maxptime:",tmp,sizeof(tmp))){ s->max_ptime=atoi(tmp); if (s->max_ptime < 10 || s->max_ptime > 100 ) { ms_warning("MSBV16Enc: unknown value [%i] for maxptime, use default value (100) instead",s->max_ptime); s->max_ptime=100; } ms_message("MSBV16Enc: got maxptime=%i",s->max_ptime); }else if (fmtp_get_value(fmtp,"ptime",tmp,sizeof(tmp))){ int val = atoi(tmp); return enc_set_ptime(f,&val); } return 0; }
static int enc_add_fmtp(MSFilter *f, void *arg){ const char *fmtp=(const char *)arg; char tmp[30]; if (fmtp_get_value(fmtp,"ptime",tmp,sizeof(tmp))){ return set_ptime(f,atoi(tmp)); } return 0; }
static int enc_add_fmtp(MSFilter *f, void *arg){ EncData *d=(EncData*)f->data; const char *fmtp=(const char *)arg; char value[12]; if (fmtp_get_value(fmtp,"packetization-mode",value,sizeof(value))){ d->mode=atoi(value); ms_message("packetization-mode set to %i",d->mode); } return 0; }
static int enc_add_fmtp(MSFilter *f, void *arg){ const char *fmtp=(const char *)arg; AlawEncData *s=(AlawEncData*)f->data; char tmp[30]; if (fmtp_get_value(fmtp,"ptime",tmp,sizeof(tmp))){ s->ptime=atoi(tmp); ms_message("MSAlawEnc: got ptime=%i",s->ptime); } return 0; }
static int ms_opus_dec_add_fmtp(MSFilter *f, void *arg) { OpusDecData *d = (OpusDecData *)f->data; const char *fmtp = (const char *)arg; char buf[32]; memset(buf, '\0', sizeof(buf)); if (fmtp_get_value(fmtp, "plc", buf, sizeof(buf))) { d->plc = atoi(buf); } return 0; }
static PayloadType * find_payload_type_best_match(const MSList *l, const PayloadType *refpt) { PayloadType *pt; char value[10]; const MSList *elem; PayloadType *candidate=NULL; for (elem=l; elem!=NULL; elem=elem->next) { pt=(PayloadType*)elem->data; /*workaround a bug in earlier versions of linphone where opus/48000/1 is offered, which is uncompliant with opus rtp draft*/ if (refpt->mime_type && strcasecmp(refpt->mime_type,"opus")==0 && refpt->channels==1 && strcasecmp(pt->mime_type,refpt->mime_type)==0) { pt->channels=1; /*so that we respond with same number of channels */ candidate=pt; break; } /* the compare between G729 and G729A is for some stupid uncompliant phone*/ if ( pt->mime_type && refpt->mime_type && (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 && pt->channels==refpt->channels) { candidate=pt; /*good candidate, check fmtp for H264 */ if (strcasecmp(pt->mime_type,"H264")==0) { if (pt->recv_fmtp!=NULL && refpt->recv_fmtp!=NULL) { int mode1=0,mode2=0; if (fmtp_get_value(pt->recv_fmtp,"packetization-mode",value,sizeof(value))) { mode1=atoi(value); } if (fmtp_get_value(refpt->recv_fmtp,"packetization-mode",value,sizeof(value))) { mode2=atoi(value); } if (mode1==mode2) break; /*exact match */ } } else break; } } return candidate; }
static int enc_add_fmtp(MSFilter *f, void *arg){ char buf[64]; const char *fmtp=(const char *)arg; EncState *s=(EncState*)f->data; memset(buf, '\0', sizeof(buf)); if (fmtp_get_value(fmtp, "mode", buf, sizeof(buf))){ if (buf[0]=='\0'){ ms_warning("unsupported fmtp parameter (%s)!", fmtp); return 0; } ms_message("iLBC encoder got mode=%s",buf); if (strstr(buf,"20")!=NULL){ s->nsamples=BLOCKL_20MS; s->nbytes=NO_OF_BYTES_20MS; s->ms_per_frame=20; }else if (strstr(buf,"30")!=NULL){ s->nsamples=BLOCKL_30MS; s->nbytes=NO_OF_BYTES_30MS; s->ms_per_frame=30; } } if (fmtp_get_value(fmtp,"ptime",buf,sizeof(buf))){ int ptime; if (buf[0]=='\0'){ ms_warning("unsupported fmtp parameter (%s)!", fmtp); return 0; } ms_message("iLBC encoder got ptime=%s",buf); ptime=atoi(buf); if (ptime>=20 && ptime<=140){ s->ptime=ptime; } } return 0; }
static int enc_add_fmtp(MSFilter *obj, void *arg) { char buf[64]; const char *fmtp = (const char *) arg; EncState *s = (EncState*) obj->data; memset(buf, '\0', sizeof (buf)); if (fmtp_get_value(fmtp, "ptime", buf, sizeof (buf))) { s->ptime = atoi(buf); //if the ptime is not a mulptiple of 20, go to the next multiple if (s->ptime % 20) s->ptime = s->ptime - s->ptime % 20 + 20; ms_message("AMR-WB: got ptime=%i", s->ptime); } return 0; }
static int dec_add_fmtp(MSFilter *f, void *arg){ DecData *d=(DecData*)f->data; const char *fmtp=(const char *)arg; char value[256]; if (fmtp_get_value(fmtp,"sprop-parameter-sets",value,sizeof(value))){ char * b64_sps=value; char * b64_pps=strchr(value,','); if (b64_pps){ *b64_pps='\0'; ++b64_pps; ms_message("Got sprop-parameter-sets : sps=%s , pps=%s",b64_sps,b64_pps); d->sps=allocb(sizeof(value),0); d->sps->b_wptr+=b64_decode(b64_sps,strlen(b64_sps),d->sps->b_wptr,sizeof(value)); d->pps=allocb(sizeof(value),0); d->pps->b_wptr+=b64_decode(b64_pps,strlen(b64_pps),d->pps->b_wptr,sizeof(value)); } } return 0; }
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; }