static void generic_plc_process(MSFilter *f) { generic_plc_struct *mgps=(generic_plc_struct*)f->data; unsigned int buff_size = mgps->rate*sizeof(int16_t)*mgps->nchannels*f->ticker->interval/1000; mblk_t *m; while((m=ms_queue_get(f->inputs[0]))!=NULL){ int transitionBufferSize = mgps->rate*sizeof(int16_t)*TRANSITION_DELAY/1000; unsigned char buf[128]; unsigned int time = (1000*(m->b_wptr - m->b_rptr))/(mgps->rate*sizeof(int16_t)*mgps->nchannels); ms_concealer_inc_sample_time(mgps->concealer, f->ticker->time, time, TRUE); /* introduce 16 sample delay (2ms) */ memcpy(buf, m->b_wptr-transitionBufferSize, transitionBufferSize); memmove(m->b_rptr+transitionBufferSize, m->b_rptr, m->b_wptr - m->b_rptr - transitionBufferSize); memcpy(m->b_rptr, mgps->continuity_buffer, transitionBufferSize); memcpy(mgps->continuity_buffer, buf, transitionBufferSize); if (mgps->cng_running){ /*we were doing CNG, now resuming with normal audio*/ int16_t continuity_buffer[80]; #ifdef HAVE_G729B bcg729Decoder(mgps->decoderChannelContext, NULL, 0, 1, 1, 1, continuity_buffer); #else memset (continuity_buffer, 0, 80*sizeof(int16_t)); #endif memcpy(m->b_rptr, continuity_buffer, transitionBufferSize); generic_plc_transition_mix((int16_t *)(m->b_rptr+transitionBufferSize), &(continuity_buffer[mgps->rate*TRANSITION_DELAY/1000]), mgps->rate*TRANSITION_DELAY/1000); mgps->cng_running=FALSE; mgps->cng_set=FALSE; } ms_queue_put(f->outputs[0], m); } if (ms_concealer_context_is_concealement_required(mgps->concealer, f->ticker->time)) { #ifdef HAVE_G729B m = allocb(buff_size, 0); /* Transmitted CNG data is in mgps->cng_data : give it to bcg729 decoder -> output in m->b_wptr */ if (mgps->cng_set) { /* received some CNG data */ mgps->cng_set=FALSE; /* reset flag */ mgps->cng_running=TRUE; bcg729Decoder(mgps->decoderChannelContext, mgps->cng_data.data, mgps->cng_data.datasize, 0, 1, 1, (int16_t *)(m->b_wptr)); mblk_set_cng_flag(m, 1); generic_plc_transition_mix((int16_t *)m->b_wptr, (int16_t *)mgps->continuity_buffer, mgps->rate*TRANSITION_DELAY/1000); /* TODO: if ticker->interval is not 10 ms which is also G729 frame length, we must generate untransmitted frame CNG until we reach the requested data amount */ } else if (mgps->cng_running) { /* missing frame but CNG is ongoing: shall be an untransmitted frame */ bcg729Decoder(mgps->decoderChannelContext, NULL, 0, 1, 1, 1, (int16_t *)(m->b_wptr)); mblk_set_cng_flag(m, 1); } else { mblk_set_plc_flag(m, 1); memset(m->b_wptr, 0, buff_size); } #else m = allocb(buff_size, 0); if (!mgps->cng_running && mgps->cng_set){ mgps->cng_running=TRUE; mblk_set_cng_flag(m, 1); /*TODO do something with the buffer*/ }else{ mblk_set_plc_flag(m, 1); } memset(m->b_wptr, 0, buff_size); #endif m->b_wptr += buff_size; ms_queue_put(f->outputs[0], m); ms_concealer_inc_sample_time(mgps->concealer, f->ticker->time, f->ticker->interval, FALSE); } }
void generic_plc_generate_samples(plc_context_t *context, int16_t *data, uint16_t sample_nbr) { uint16_t continuity_buffer_sample_nbr = context->sample_rate*TRANSITION_DELAY/1000; /* shall we just set everything to 0 */ if (context->plc_samples_used>=MAX_PLC_LEN*context->sample_rate/1000) { context->plc_samples_used += sample_nbr; memset(data, 0, sample_nbr*sizeof(int16_t)); memset(context->continuity_buffer, 0, 2*continuity_buffer_sample_nbr*sizeof(int16_t)); return; } /* it's the first missing packet, we must generate samples */ if (context->plc_samples_used == 0) { /* generate samples based on the plc_buffer(previously received signal)*/ generic_plc_fftbf(context, (int16_t *)context->plc_buffer, context->plc_out_buffer, context->sample_rate*PLC_BUFFER_LEN); /* mix with continuity buffer */ generic_plc_transition_mix(context->plc_out_buffer, (int16_t *)context->continuity_buffer, continuity_buffer_sample_nbr); } /* we being asked for more sample than we have in the buffer (save some for continuity buffer, we must have twice the TRANSITION_DELAY in buffer) */ if (context->plc_index + sample_nbr + continuity_buffer_sample_nbr*2 > 2*context->sample_rate*PLC_BUFFER_LEN ) { uint16_t samples_ready_nbr = 2*context->sample_rate*PLC_BUFFER_LEN - context->plc_index - continuity_buffer_sample_nbr; if (samples_ready_nbr>sample_nbr) { /* we had more than one but less than two TRANSITION_DELAY ms in buffer */ samples_ready_nbr=sample_nbr; } /* copy all the remaining sample to the data buffer (save some for continuity) */ memcpy(data, context->plc_out_buffer+context->plc_index, samples_ready_nbr*sizeof(int16_t)); memcpy(context->continuity_buffer, context->plc_out_buffer+context->plc_index+samples_ready_nbr, continuity_buffer_sample_nbr * sizeof(int16_t)); /* generate sample based on the plc_out_buffer(previously generated signal) */ generic_plc_fftbf(context, context->plc_out_buffer, context->plc_out_buffer, context->sample_rate*PLC_BUFFER_LEN); /* mix with continuity buffer */ generic_plc_transition_mix(context->plc_out_buffer, (int16_t *)context->continuity_buffer, continuity_buffer_sample_nbr); /* copy the rest of requested samples to the data buffer */ if (sample_nbr!=samples_ready_nbr) { memcpy(data+samples_ready_nbr, context->plc_out_buffer, (sample_nbr - samples_ready_nbr)*sizeof(int16_t)); } context->plc_index = sample_nbr - samples_ready_nbr; /* manage continuity buffer */ memcpy(context->continuity_buffer, context->plc_out_buffer + context->plc_index, 2*continuity_buffer_sample_nbr * sizeof(int16_t)); } else { /* copy the requested amount of data to the given buffer and update continuity buffer */ memcpy(data, context->plc_out_buffer+context->plc_index, sample_nbr*sizeof(int16_t)); context->plc_index += sample_nbr; /* update continuity buffer */ memcpy(context->continuity_buffer, context->plc_out_buffer + context->plc_index, 2*continuity_buffer_sample_nbr * sizeof(int16_t)); } /* adjust volume when PLC_DECREASE_START samples point is reached */ if ( context->plc_samples_used + sample_nbr > PLC_DECREASE_START*context->sample_rate/1000 ) { int i = PLC_DECREASE_START*context->sample_rate/1000 - context->plc_samples_used; if (i<0) i=0; for (; i<sample_nbr; i++) { if (context->plc_samples_used+i>=MAX_PLC_LEN*context->sample_rate/1000) { data[i] = 0; } else { data[i] = (int16_t)((1.0+((float)(PLC_DECREASE_START*context->sample_rate/1000 - (context->plc_samples_used + i))/(float)((MAX_PLC_LEN-PLC_DECREASE_START)*context->sample_rate/1000))) * (float)data[i]); } } } context->plc_samples_used += sample_nbr; }
static void generic_plc_process(MSFilter *f) { generic_plc_struct *mgps=(generic_plc_struct*)f->data; plc_context_t *plc_context = mgps->plc_context; mblk_t *m; while((m=ms_queue_get(f->inputs[0]))!=NULL){ int transitionBufferSize = mgps->rate*sizeof(int16_t)*TRANSITION_DELAY/1000; size_t msg_size = msgdsize(m); unsigned int time = (unsigned int)((1000*msg_size)/(mgps->rate*sizeof(int16_t)*mgps->nchannels)); ms_concealer_inc_sample_time(mgps->concealer, f->ticker->time, time, TRUE); /* Store current msg in plc_buffer */ generic_plc_update_plc_buffer(plc_context, m->b_rptr, msg_size); /* introduce delay (TRANSITION_DELAY ms) */ generic_plc_update_continuity_buffer(plc_context, m->b_rptr, msg_size); if (mgps->cng_running){ /*we were doing CNG, now resuming with normal audio*/ int16_t continuity_buffer[80]; #ifdef HAVE_G729B bcg729Decoder(mgps->decoderChannelContext, NULL, 0, 1, 1, 1, continuity_buffer); #else memset (continuity_buffer, 0, 80*sizeof(int16_t)); #endif memcpy(m->b_rptr, continuity_buffer, transitionBufferSize); generic_plc_transition_mix((int16_t *)(m->b_rptr+transitionBufferSize), continuity_buffer, mgps->rate*TRANSITION_DELAY/1000); mgps->cng_running=FALSE; mgps->cng_set=FALSE; } if (plc_context->plc_samples_used!=0) { /*we were doing PLC, now resuming with normal audio, continuity buffer is twice the transition delay lengths, * the second half is untouched by the update function and contains transition data generated by PLC */ generic_plc_transition_mix((int16_t *)(m->b_rptr+transitionBufferSize), (int16_t *)(plc_context->continuity_buffer+transitionBufferSize), mgps->rate*TRANSITION_DELAY/1000); } plc_context->plc_index=0; plc_context->plc_samples_used=0; ms_queue_put(f->outputs[0], m); } if (ms_concealer_context_is_concealement_required(mgps->concealer, f->ticker->time)) { unsigned int buff_size = mgps->rate*sizeof(int16_t)*mgps->nchannels*f->ticker->interval/1000; #ifdef HAVE_G729B m = allocb(buff_size, 0); /* Transmitted CNG data is in mgps->cng_data : give it to bcg729 decoder -> output in m->b_wptr */ if (mgps->cng_set) { /* received some CNG data */ mgps->cng_set=FALSE; /* reset flag */ mgps->cng_running=TRUE; bcg729Decoder(mgps->decoderChannelContext, mgps->cng_data.data, mgps->cng_data.datasize, 0, 1, 1, (int16_t *)(m->b_wptr)); mblk_set_cng_flag(m, 1); generic_plc_transition_mix((int16_t *)m->b_wptr, (int16_t *)plc_context->continuity_buffer, mgps->rate*TRANSITION_DELAY/1000); /* TODO: if ticker->interval is not 10 ms which is also G729 frame length, we must generate untransmitted frame CNG until we reach the requested data amount */ } else if (mgps->cng_running) { /* missing frame but CNG is ongoing: shall be an untransmitted frame */ bcg729Decoder(mgps->decoderChannelContext, NULL, 0, 1, 1, 1, (int16_t *)(m->b_wptr)); mblk_set_cng_flag(m, 1); } else { /* plc */ mblk_set_plc_flag(m, 1); generic_plc_generate_samples(plc_context, (int16_t *)m->b_wptr, buff_size/sizeof(int16_t)); /* store the generated samples into plc_buffer */ generic_plc_update_plc_buffer(plc_context, m->b_wptr, buff_size); //memset(m->b_wptr, 0, buff_size); } #else m = allocb(buff_size, 0); if (mgps->cng_set){ mgps->cng_set=FALSE; /* reset flag */ mgps->cng_running=TRUE; mblk_set_cng_flag(m, 1); /*TODO do something with the buffer*/ memset(m->b_wptr, 0, buff_size); } else if (mgps->cng_running) { /* missing frame but CNG is ongoing: shall be an untransmitted frame */ memset(m->b_wptr, 0, buff_size); mblk_set_cng_flag(m, 1); }else{ /* plc */ mblk_set_plc_flag(m, 1); generic_plc_generate_samples(plc_context, (int16_t *)m->b_wptr, buff_size/sizeof(int16_t)); /* store the generated samples into plc_buffer */ generic_plc_update_plc_buffer(plc_context, m->b_wptr, buff_size); //memset(m->b_wptr, 0, buff_size); } #endif m->b_wptr += buff_size; ms_queue_put(f->outputs[0], m); ms_concealer_inc_sample_time(mgps->concealer, f->ticker->time, f->ticker->interval, FALSE); } }