void AmJbPlayout::prepare_buffer(unsigned int audio_buffer_ts, unsigned int ms) { ShortSample buf[AUDIO_BUFFER_SIZE]; unsigned int ts; unsigned int nb_samples; /** * Get all RTP packets that correspond to the required interval, * decode them and put into playout buffer. */ while (m_jb.get(audio_buffer_ts, ms, buf, &nb_samples, &ts)) { direct_write_buffer(ts, buf, nb_samples); m_plcbuffer->add_to_history(buf, PCM16_S2B(nb_samples)); /* Conceal the gap between previous and current RTP packets */ if (last_ts_i && ts_less()(m_last_rtp_endts, ts)) { int concealed_size = m_plcbuffer->conceal_loss(ts - m_last_rtp_endts, (unsigned char *)buf); if (concealed_size > 0) direct_write_buffer(m_last_rtp_endts, buf, PCM16_B2S(concealed_size)); } m_last_rtp_endts = ts + nb_samples; last_ts_i = true; } if (!last_ts_i) { return; } if (ts_less()(m_last_rtp_endts, audio_buffer_ts + ms)) { /* Last packets have been lost. Conceal them */ int concealed_size = m_plcbuffer->conceal_loss(audio_buffer_ts + ms - m_last_rtp_endts, (unsigned char *)buf); if (concealed_size > 0) direct_write_buffer(m_last_rtp_endts, buf, PCM16_B2S(concealed_size)); m_last_rtp_endts = audio_buffer_ts + ms; } }
// returns bytes read, else -1 if error (0 is OK) int RtmpAudio::get(unsigned long long system_ts, unsigned char* buffer, int output_sample_rate, unsigned int nb_samples) { // - buffer RTMP audio // - read from RTMP recv buffer unsigned int user_ts = scaleSystemTS(system_ts); //DBG("get(%u, %u)\n",user_ts,nb_samples); process_recv_queue(user_ts); nb_samples = (unsigned int)((float)nb_samples * (float)getSampleRate() / (float)output_sample_rate); u_int32_t size = PCM16_S2B(playout_buffer.read(user_ts, (ShortSample*)((unsigned char*)samples), nb_samples)); if(output_sample_rate != getSampleRate()) { size = resampleOutput((unsigned char*)samples, size, getSampleRate(), output_sample_rate); } memcpy(buffer,(unsigned char*)samples,size); return size; }
int AmBufferedAudio::get(unsigned int user_ts, unsigned char* buffer, unsigned int nb_samples) { if (!output_buffer_size) return AmAudio::get(user_ts, buffer, nb_samples); if (w-r < low_buffer_thresh && !eof) { input_get_audio(user_ts); } size_t nget = PCM16_S2B(nb_samples); if (w-r < nget) nget = w-r; if (!nget) { // empty buffer and input error if (eof) return err_code; // empty buffer but no input error return 0; } memcpy(buffer, &output_buffer[r], nget); r+=nget; return nget; }
int AmRtpAudio::get(unsigned long long system_ts, unsigned char* buffer, int output_sample_rate, unsigned int nb_samples) { if (!(receiving || getPassiveMode())) return 0; // like nothing received int ret = receive(system_ts); if(ret < 0) return ret; // like nothing received? if (!active) return 0; unsigned int user_ts = scaleSystemTS(system_ts); nb_samples = (unsigned int)((float)nb_samples * (float)getSampleRate() / (float)output_sample_rate); u_int32_t size = PCM16_S2B(playout_buffer->read(user_ts, (ShortSample*)((unsigned char*)samples), nb_samples)); if(output_sample_rate != getSampleRate()) { size = resampleOutput((unsigned char*)samples, size, getSampleRate(), output_sample_rate); } memcpy(buffer,(unsigned char*)samples,size); return size; }
unsigned int AmAudio::downMix(unsigned int size) { unsigned int s = size; if(fmt->channels == 2){ stereo2mono(samples.back_buffer(),(unsigned char*)samples,s); samples.swap(); } #ifdef USE_LIBSAMPLERATE if (fmt->rate != SYSTEM_SAMPLERATE) { if (!resample_state) { int src_error; // for better quality but more CPU usage, use SRC_SINC_ converters resample_state = src_new(SRC_LINEAR, 1, &src_error); if (!resample_state) { ERROR("samplerate initialization error: "); } } if (resample_state) { if (resample_buf_samples + PCM16_B2S(s) > PCM16_B2S(AUDIO_BUFFER_SIZE) * 2) { WARN("resample input buffer overflow! (%d)\n", resample_buf_samples + PCM16_B2S(s)); } else { signed short* samples_s = (signed short*)(unsigned char*)samples; src_short_to_float_array(samples_s, &resample_in[resample_buf_samples], PCM16_B2S(s)); resample_buf_samples += PCM16_B2S(s); } SRC_DATA src_data; src_data.data_in = resample_in; src_data.input_frames = resample_buf_samples; src_data.data_out = resample_out; src_data.output_frames = PCM16_B2S(AUDIO_BUFFER_SIZE); src_data.src_ratio = (double)SYSTEM_SAMPLERATE / (double)fmt->rate; src_data.end_of_input = 0; int src_err = src_process(resample_state, &src_data); if (src_err) { DBG("resample error: '%s'\n", src_strerror(src_err)); }else { signed short* samples_s = (signed short*)(unsigned char*)samples; src_float_to_short_array(resample_out, samples_s, src_data.output_frames_gen); s = PCM16_S2B(src_data.output_frames_gen); if (resample_buf_samples != (unsigned int)src_data.input_frames_used) { memmove(resample_in, &resample_in[src_data.input_frames_used], (resample_buf_samples - src_data.input_frames_used) * sizeof(float)); } resample_buf_samples = resample_buf_samples - src_data.input_frames_used; } } } #endif return s; }
void Packet::init(const ShortSample *data, unsigned int size, unsigned int ts) { size = PCM16_S2B(size); if (size > sizeof(m_data)) size = sizeof(m_data); m_size = PCM16_B2S(size); memcpy(m_data, data, size); m_ts = ts; }
void AmPlayoutBuffer::write(u_int32_t ref_ts, u_int32_t rtp_ts, int16_t* buf, u_int32_t len, bool begin_talk) { unsigned int mapped_ts; if(!recv_offset_i) { recv_offset = rtp_ts - ref_ts; recv_offset_i = true; DBG("initialized recv_offset with %u (%u - %u)\n", recv_offset, ref_ts, rtp_ts); mapped_ts = r_ts = w_ts = ref_ts; } else { mapped_ts = rtp_ts - recv_offset; // resync if( ts_less()(mapped_ts, ref_ts - MAX_DELAY/2) || !ts_less()(mapped_ts, ref_ts + MAX_DELAY) ){ DBG("resync needed: reference ts = %u; write ts = %u\n", ref_ts, mapped_ts); recv_offset = rtp_ts - ref_ts; mapped_ts = r_ts = w_ts = ref_ts; } } if(!last_ts_i) { last_ts = mapped_ts; last_ts_i = true; } if(ts_less()(last_ts, mapped_ts) && !begin_talk && (mapped_ts - last_ts <= PLC_MAX_SAMPLES)) { unsigned char tmp[AUDIO_BUFFER_SIZE * 2]; int l_size = m_plcbuffer->conceal_loss(mapped_ts - last_ts, tmp); if (l_size>0) { direct_write_buffer(last_ts, (ShortSample*)tmp, PCM16_B2S(l_size)); } } write_buffer(ref_ts, mapped_ts, buf, len); m_plcbuffer->add_to_history(buf, PCM16_S2B(len)); // update last_ts to end of received packet // if not out-of-sequence if (ts_less()(last_ts, mapped_ts) || last_ts == mapped_ts) last_ts = mapped_ts + len; }
unsigned int AmInternalResamplerState::resample(unsigned char *samples, unsigned int s, double ratio) { if (rstate == NULL) { ERROR("Uninitialized resampling state"); return s; } //DBG("Resampling with ration %f", ratio); //DBG("Putting %d samples in the buffer", PCM16_B2S(s)); rstate->put_samples((signed short *)samples, PCM16_B2S(s)); s = rstate->resample((signed short *)samples, ratio, PCM16_B2S(s) * ratio); //DBG("Returning %d samples", s); return PCM16_S2B(s); }
unsigned int AmRtpAudio::conceal_loss(unsigned int ts_diff, unsigned char *buffer) { int s=0; if(!use_default_plc){ amci_codec_t* codec = fmt->getCodec(); long h_codec = fmt->getHCodec(); assert(codec && codec->plc); s = (*codec->plc)(buffer, PCM16_S2B(ts_diff), fmt->channels,getSampleRate(),h_codec); DBG("codec specific PLC (ts_diff = %i; s = %i)\n",ts_diff,s); } else { s = default_plc(buffer, PCM16_S2B(ts_diff), fmt->channels,getSampleRate()); DBG("default PLC (ts_diff = %i; s = %i)\n",ts_diff,s); } return s; }
void AmMultiPartyMixer::GetChannelPacket(unsigned int channel_id, unsigned long long system_ts, unsigned char* buffer, unsigned int& size, unsigned int& output_sample_rate) { if (!size) return; assert(size <= AUDIO_BUFFER_SIZE); unsigned int last_ts = system_ts + (PCM16_B2S(size) * (WALLCLOCK_RATE/100) / (GetCurrentSampleRate()/100)); std::deque<MixerBufferState>::iterator bstate = findBufferStateForReading(GetCurrentSampleRate(), last_ts); SampleArrayShort* channel = 0; if(bstate != buffer_state.end() && (channel = bstate->get_channel(channel_id)) != 0) { unsigned int samples = PCM16_B2S(size) * (bstate->sample_rate/100) / (GetCurrentSampleRate()/100); assert(samples <= PCM16_B2S(AUDIO_BUFFER_SIZE)); unsigned long long cur_ts = system_ts * (bstate->sample_rate/100) / (WALLCLOCK_RATE/100); bstate->mixed_channel->get(cur_ts,tmp_buffer,samples); channel->get(cur_ts,(short*)buffer,samples); mix_sub(tmp_buffer,tmp_buffer,(short*)buffer,samples); scale((short*)buffer,tmp_buffer,samples); size = PCM16_S2B(samples); output_sample_rate = bstate->sample_rate; } else if (bstate != buffer_state.end()) { memset(buffer,0,size); output_sample_rate = GetCurrentSampleRate(); //DBG("XXDebugMixerXX: GetChannelPacket returned zeroes, ts=%u, last_ts=%u, output_sample_rate=%u", ts, last_ts, output_sample_rate); } else { /* ERROR("XXDebugMixerXX: MultiPartyMixer::GetChannelPacket: " "channel #%i doesn't exist\n",channel_id); DBG("XXDebugMixerXX: GetChannelPacket failed, ts=%u", ts); for (std::deque<MixerBufferState>::iterator it = buffer_state.begin(); it != buffer_state.end(); it++) { DEBUG_MIXER_BUFFER_STATE(*it, "on GetChannelPacket failure"); }*/ } cleanupBufferStates(last_ts); }
unsigned int AmRtpAudio::default_plc(unsigned char* out_buf, unsigned int size, unsigned int channels, unsigned int sample_rate) { short* buf_offset = (short*)out_buf; #ifdef USE_SPANDSP_PLC plc_fillin(plc_state, buf_offset, PCM16_B2S(size)); #else for(unsigned int i=0; i<(PCM16_B2S(size)/FRAMESZ); i++){ fec->dofe(buf_offset); buf_offset += FRAMESZ; } #endif // USE_SPANDSP_PLC return PCM16_S2B(buf_offset - (short*)out_buf); }
/** * This method will return from zero to several packets. * To get all the packets for the single ts the caller must call this * method with the same ts till the return value will become false. */ bool AmJitterBuffer::get(unsigned int ts, unsigned int ms, ShortSample *out_buf, unsigned int *out_size, unsigned int *out_ts) { bool retval = true; m_mutex.lock(); if (!m_tsInited) { m_mutex.unlock(); return false; } if (!m_tsDeltaInited || m_forceResync) { m_tsDelta = m_lastTs - ts + ms; m_tsDeltaInited = true; m_lastAudioTs = ts; m_forceResync = false; #ifdef DEBUG_PLAYOUTBUF DBG("Jitter buffer: initialized tsDelta with %u\n", m_tsDelta); m_tsDeltaStart = m_tsDelta; #endif } else if (m_lastAudioTs != ts && m_lastResyncTs != m_lastTs) { if (ts_less()(ts + m_tsDelta, m_lastTs)) { /* * New packet arrived earlier than expected - * immediate resync required */ m_tsDelta += m_lastTs - ts + ms; #ifdef DEBUG_PLAYOUTBUF DBG("Jitter buffer resynced forward (-> %d rel)\n", m_tsDelta - m_tsDeltaStart); #endif m_delayCount = 0; } else if (ts_less()(m_lastTs, ts + m_tsDelta - m_jitter / 2)) { /* New packet hasn't arrived yet */ if (m_delayCount > RESYNC_THRESHOLD) { unsigned int d = m_tsDelta -(m_lastTs - ts + ms); m_tsDelta -= d / 2; #ifdef DEBUG_PLAYOUTBUF DBG("Jitter buffer resynced backward (-> %d rel)\n", m_tsDelta - m_tsDeltaStart); #endif } else ++m_delayCount; } else { /* New packet arrived at proper time */ m_delayCount = 0; } m_lastResyncTs = m_lastTs; } m_lastAudioTs = ts; unsigned int get_ts = ts + m_tsDelta - m_jitter; // DBG("Getting pkt at %u, res ts = %u\n", get_ts / m_frameSize, p.timestamp); // First of all throw away all too old packets from the head Packet *tmp; for (tmp = m_head; tmp && ts_less()(tmp->ts() + tmp->size(), get_ts); ) { m_head = tmp->m_next; if (m_head == NULL) m_tail = NULL; else m_head->m_prev = NULL; m_allocator.free(tmp); tmp = m_head; } // Get the packet from the head if (m_head && ts_less()(m_head->ts(), get_ts + ms)) { tmp = m_head; m_head = tmp->m_next; if (m_head == NULL) m_tail = NULL; else m_head->m_prev = NULL; memcpy(out_buf, tmp->data(), PCM16_S2B(tmp->size())); // Map RTP timestamp to internal audio timestamp *out_ts = tmp->ts() - m_tsDelta + m_jitter; *out_size = tmp->size(); m_allocator.free(tmp); } else retval = false; m_mutex.unlock(); return retval; }