void JackLayer::read(AudioBuffer &buffer) { for (unsigned i = 0; i < in_ringbuffers_.size(); ++i) { const size_t incomingSamples = jack_ringbuffer_read_space(in_ringbuffers_[i]) / sizeof(captureFloatBuffer_[0]); if (!incomingSamples) continue; captureFloatBuffer_.resize(incomingSamples); buffer.resize(incomingSamples); // write to output const size_t from_ringbuffer = jack_ringbuffer_read_space(in_ringbuffers_[i]); const size_t expected_bytes = std::min(incomingSamples * sizeof(captureFloatBuffer_[0]), from_ringbuffer); // FIXME: while we have samples to write AND while we have space to write them const size_t read_bytes = jack_ringbuffer_read(in_ringbuffers_[i], (char *) captureFloatBuffer_.data(), expected_bytes); if (read_bytes < expected_bytes) { RING_WARN("Dropped %zu bytes", expected_bytes - read_bytes); break; } /* Write the data one frame at a time. This is * inefficient, but makes things simpler. */ // FIXME: this is braindead, we should write blocks of samples at a time // convert a vector of samples from 1 channel to a float vector convertFromFloat(captureFloatBuffer_, *buffer.getChannel(i)); } }
void AudioSender::process() { auto& mainBuffer = Manager::instance().getRingBufferPool(); auto mainBuffFormat = mainBuffer.getInternalAudioFormat(); // compute nb of byte to get corresponding to 1 audio frame const std::size_t samplesToGet = std::chrono::duration_cast<std::chrono::seconds>(mainBuffFormat.sample_rate * secondsPerPacket_).count(); if (mainBuffer.availableForGet(id_) < samplesToGet) { const auto wait_time = std::chrono::duration_cast<std::chrono::milliseconds>(secondsPerPacket_); if (not mainBuffer.waitForDataAvailable(id_, samplesToGet, wait_time)) return; } // get data micData_.setFormat(mainBuffFormat); micData_.resize(samplesToGet); const auto samples = mainBuffer.getData(micData_, id_); if (samples != samplesToGet) return; // down/upmix as needed auto accountAudioCodec = std::static_pointer_cast<AccountAudioCodecInfo>(args_.codec); micData_.setChannelNum(accountAudioCodec->audioformat.nb_channels, true); if (mainBuffFormat.sample_rate != accountAudioCodec->audioformat.sample_rate) { if (not resampler_) { RING_DBG("Creating audio resampler"); resampler_.reset(new Resampler(accountAudioCodec->audioformat)); } resampledData_.setFormat(accountAudioCodec->audioformat); resampledData_.resize(samplesToGet); resampler_->resample(micData_, resampledData_); Smartools::getInstance().setLocalAudioCodec(audioEncoder_->getEncoderName()); if (audioEncoder_->encode_audio(resampledData_) < 0) RING_ERR("encoding failed"); } else { if (audioEncoder_->encode_audio(micData_) < 0) RING_ERR("encoding failed"); } }
void JackLayer::fillWithUrgent(AudioBuffer &buffer, size_t samplesToGet) { // Urgent data (dtmf, incoming call signal) come first. samplesToGet = std::min(samplesToGet, hardwareBufferSize_); buffer.resize(samplesToGet); urgentRingBuffer_.get(buffer, RingBufferPool::DEFAULT_ID); buffer.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_); // Consume the regular one as well (same amount of samples) Manager::instance().getRingBufferPool().discard(samplesToGet, RingBufferPool::DEFAULT_ID); }
size_t OpenSLLayer::audioPlaybackFillWithVoice(AudioBuffer &buffer) { RingBufferPool &mainBuffer = Manager::instance().getRingBufferPool(); size_t got = mainBuffer.getAvailableData(buffer, RingBufferPool::DEFAULT_ID); buffer.resize(got); buffer.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_); if (audioFormat_.sample_rate != mainBuffer.getInternalSamplingRate()) { DEBUG("OpenSLLayer::audioPlaybackFillWithVoice sample_rate != mainBuffer.getInternalSamplingRate() \n"); AudioBuffer out(buffer, false); out.setSampleRate(audioFormat_.sample_rate); resampler_->resample(buffer, out); buffer = out; } return buffer.size(); }
void JackLayer::fillWithVoice(AudioBuffer &buffer, size_t samplesAvail) { RingBufferPool &mainBuffer = Manager::instance().getRingBufferPool(); buffer.resize(samplesAvail); mainBuffer.getData(buffer, RingBufferPool::DEFAULT_ID); buffer.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_); if (audioFormat_.sample_rate != (unsigned) mainBuffer.getInternalSamplingRate()) { RING_DBG("fillWithVoice sample_rate != mainBuffer.getInternalSamplingRate() \n"); AudioBuffer out(buffer, false); out.setSampleRate(audioFormat_.sample_rate); resampler_->resample(buffer, out); buffer = out; } }
void JackLayer::fillWithToneOrRingtone(AudioBuffer &buffer) { buffer.resize(hardwareBufferSize_); AudioLoop *tone = Manager::instance().getTelephoneTone(); AudioLoop *file_tone = Manager::instance().getTelephoneFile(); // In case of a dtmf, the pointers will be set to nullptr once the dtmf length is // reached. For this reason we need to fill audio buffer with zeros if pointer is nullptr if (tone) { tone->getNext(buffer, playbackGain_); } else if (file_tone) { file_tone->getNext(buffer, playbackGain_); } else { buffer.reset(); } }
size_t RingBufferPool::getAvailableData(AudioBuffer& buffer, const std::string& call_id) { std::lock_guard<std::recursive_mutex> lk(stateLock_); auto bindings = getReadBindings(call_id); if (not bindings) return 0; // No mixing if (bindings->size() == 1) { return (*bindings->cbegin())->get(buffer, call_id); } size_t availableSamples = std::numeric_limits<size_t>::max(); for (const auto& rbuf : *bindings) availableSamples = std::min(availableSamples, rbuf->availableForGet(call_id)); if (availableSamples == std::numeric_limits<size_t>::max()) return 0; availableSamples = std::min(availableSamples, buffer.frames()); buffer.resize(availableSamples); buffer.reset(); buffer.setFormat(internalAudioFormat_); AudioBuffer mixBuffer(buffer); for (const auto &rbuf : *bindings) { if (rbuf->get(mixBuffer, call_id) > 0) buffer.mix(mixBuffer); } return availableSamples; }