diff --git a/src/media/audio/alsa/alsalayer.cpp b/src/media/audio/alsa/alsalayer.cpp index 928e20cbea97875984f212c2542d34e843820c0d..e0069c659b7e6320164707e17bef6bc84b367bc9 100644 --- a/src/media/audio/alsa/alsalayer.cpp +++ b/src/media/audio/alsa/alsalayer.cpp @@ -91,24 +91,25 @@ void AlsaThread::initAudioLayer(void) } if (not alsa_->is_capture_open_) { - alsa_->is_capture_open_ = alsa_->openDevice(&alsa_->captureHandle_, pcmc, SND_PCM_STREAM_CAPTURE); + alsa_->is_capture_open_ = alsa_->openDevice(&alsa_->captureHandle_, pcmc, SND_PCM_STREAM_CAPTURE, alsa_->audioInputFormat_); if (not alsa_->is_capture_open_) emitSignal<DRing::ConfigurationSignal::Error>(ALSA_CAPTURE_DEVICE); } if (not alsa_->is_playback_open_) { - alsa_->is_playback_open_ = alsa_->openDevice(&alsa_->playbackHandle_, pcmp, SND_PCM_STREAM_PLAYBACK); + alsa_->is_playback_open_ = alsa_->openDevice(&alsa_->playbackHandle_, pcmp, SND_PCM_STREAM_PLAYBACK, alsa_->audioFormat_); if (not alsa_->is_playback_open_) emitSignal<DRing::ConfigurationSignal::Error>(ALSA_PLAYBACK_DEVICE); if (alsa_->getIndexPlayback() != alsa_->getIndexRingtone()) - if (!alsa_->openDevice(&alsa_->ringtoneHandle_, pcmr, SND_PCM_STREAM_PLAYBACK)) + if (!alsa_->openDevice(&alsa_->ringtoneHandle_, pcmr, SND_PCM_STREAM_PLAYBACK, alsa_->audioFormat_)) emitSignal<DRing::ConfigurationSignal::Error>(ALSA_PLAYBACK_DEVICE); } alsa_->hardwareFormatAvailable(alsa_->getFormat()); + alsa_->hardwareInputFormatAvailable(alsa_->audioInputFormat_); alsa_->prepareCaptureStream(); alsa_->preparePlaybackStream(); @@ -172,7 +173,7 @@ AlsaLayer::~AlsaLayer() } // Retry approach taken from pa_linux_alsa.c, part of PortAudio -bool AlsaLayer::openDevice(snd_pcm_t **pcm, const std::string &dev, snd_pcm_stream_t stream) +bool AlsaLayer::openDevice(snd_pcm_t **pcm, const std::string &dev, snd_pcm_stream_t stream, AudioFormat& format) { RING_DBG("Alsa: Opening %s", dev.c_str()); @@ -199,7 +200,7 @@ bool AlsaLayer::openDevice(snd_pcm_t **pcm, const std::string &dev, snd_pcm_stre return false; } - if (!alsa_set_params(*pcm)) { + if (!alsa_set_params(*pcm, format)) { snd_pcm_close(*pcm); return false; } @@ -334,7 +335,7 @@ void AlsaLayer::preparePlaybackStream() is_playback_prepared_ = true; } -bool AlsaLayer::alsa_set_params(snd_pcm_t *pcm_handle) +bool AlsaLayer::alsa_set_params(snd_pcm_t *pcm_handle, AudioFormat& format) { #define TRY(call, error) do { \ if (ALSA_CALL(call, error) < 0) \ @@ -364,11 +365,12 @@ bool AlsaLayer::alsa_set_params(snd_pcm_t *pcm_handle) TRY(snd_pcm_hw_params_set_format(HW, SND_PCM_FORMAT_S16_LE), "sample format"); TRY(snd_pcm_hw_params_set_rate_resample(HW, 0), "hardware sample rate"); /* prevent software resampling */ - TRY(snd_pcm_hw_params_set_rate_near(HW, &audioFormat_.sample_rate, nullptr), "sample rate"); + TRY(snd_pcm_hw_params_set_rate_near(HW, &format.sample_rate, nullptr), "sample rate"); // TODO: use snd_pcm_query_chmaps or similar to get hardware channel num audioFormat_.nb_channels = 2; - TRY(snd_pcm_hw_params_set_channels_near(HW, &audioFormat_.nb_channels), "channel count"); + format.nb_channels = 2; + TRY(snd_pcm_hw_params_set_channels_near(HW, &format.nb_channels), "channel count"); snd_pcm_hw_params_get_buffer_size_min(hwparams, &buffer_size_min); snd_pcm_hw_params_get_buffer_size_max(hwparams, &buffer_size_max); @@ -388,8 +390,8 @@ bool AlsaLayer::alsa_set_params(snd_pcm_t *pcm_handle) snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); snd_pcm_hw_params_get_period_size(hwparams, &period_size, nullptr); - snd_pcm_hw_params_get_rate(hwparams, &audioFormat_.sample_rate, nullptr); - snd_pcm_hw_params_get_channels(hwparams, &audioFormat_.nb_channels); + snd_pcm_hw_params_get_rate(hwparams, &format.sample_rate, nullptr); + snd_pcm_hw_params_get_channels(hwparams, &format.nb_channels); RING_DBG("Was set period_size = %lu", period_size); RING_DBG("Was set buffer_size = %lu", buffer_size); @@ -402,7 +404,7 @@ bool AlsaLayer::alsa_set_params(snd_pcm_t *pcm_handle) RING_DBG("%s using format %s", (snd_pcm_stream(pcm_handle) == SND_PCM_STREAM_PLAYBACK) ? "playback" : "capture", - audioFormat_.toString().c_str() ); + format.toString().c_str() ); snd_pcm_sw_params_t *swparams = nullptr; snd_pcm_sw_params_alloca(&swparams); @@ -421,13 +423,9 @@ bool AlsaLayer::alsa_set_params(snd_pcm_t *pcm_handle) // TODO first frame causes broken pipe (underrun) because not enough data is sent // we should wait until the handle is ready void -AlsaLayer::write(AudioSample* buffer, int frames, snd_pcm_t * handle) +AlsaLayer::write(const AudioFrame& buffer, snd_pcm_t * handle) { - // Skip empty buffers - if (!frames) - return; - - int err = snd_pcm_writei(handle, (const void*)buffer, frames); + int err = snd_pcm_writei(handle, (const void*)buffer.pointer()->data[0], buffer.pointer()->nb_samples); if (err < 0) snd_pcm_recover(handle, err, 0); @@ -450,7 +448,7 @@ AlsaLayer::write(AudioSample* buffer, int frames, snd_pcm_t * handle) startPlaybackStream(); } - ALSA_CALL(snd_pcm_writei(handle, (const void*)buffer, frames), "XRUN handling failed"); + ALSA_CALL(snd_pcm_writei(handle, (const void*)buffer.pointer()->data[0], buffer.pointer()->nb_samples), "XRUN handling failed"); break; } @@ -481,18 +479,21 @@ AlsaLayer::write(AudioSample* buffer, int frames, snd_pcm_t * handle) } } -int -AlsaLayer::read(AudioSample* buffer, int frames) +std::unique_ptr<AudioFrame> +AlsaLayer::read(unsigned frames) { if (snd_pcm_state(captureHandle_) == SND_PCM_STATE_XRUN) { prepareCaptureStream(); startCaptureStream(); } - int err = snd_pcm_readi(captureHandle_, (void*)buffer, frames); + auto ret = std::make_unique<AudioFrame>(audioInputFormat_, frames); + int err = snd_pcm_readi(captureHandle_, ret->pointer()->data[0], frames); - if (err >= 0) - return err; + if (err >= 0) { + ret->pointer()->nb_samples = err; + return ret; + } switch (err) { case -EPIPE: @@ -537,7 +538,7 @@ AlsaLayer::buildDeviceTopo(const std::string &plugin, int card) } static bool -safeUpdate(snd_pcm_t *handle, int &samples) +safeUpdate(snd_pcm_t *handle, long &samples) { samples = snd_pcm_avail_update(handle); @@ -557,6 +558,7 @@ static std::vector<std::string> getValues(const std::vector<HwIDPair> &deviceMap) { std::vector<std::string> audioDeviceList; + audioDeviceList.reserve(deviceMap.size()); for (const auto & dev : deviceMap) audioDeviceList.push_back(dev.second); @@ -634,18 +636,14 @@ AlsaLayer::getAudioDeviceIndexMap(bool getCapture) const bool AlsaLayer::soundCardIndexExists(int card, DeviceType stream) { - snd_pcm_info_t *pcminfo; - snd_pcm_info_alloca(&pcminfo); - std::string name("hw:"); - std::stringstream ss; - ss << card; - name.append(ss.str()); + const std::string name("hw:" + std::to_string(card)); snd_ctl_t* handle; - if (snd_ctl_open(&handle, name.c_str(), 0) != 0) return false; + snd_pcm_info_t* pcminfo; + snd_pcm_info_alloca(&pcminfo); snd_pcm_info_set_stream(pcminfo, stream == DeviceType::PLAYBACK ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE); bool ret = snd_ctl_pcm_info(handle, pcminfo) >= 0; snd_ctl_close(handle); @@ -690,65 +688,36 @@ void AlsaLayer::capture() if (!captureHandle_ or !is_capture_running_) return; - AudioFormat mainBufferFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat(); - int toGetFrames = snd_pcm_avail_update(captureHandle_); - if (toGetFrames < 0) RING_ERR("Audio: Mic error: %s", snd_strerror(toGetFrames)); - if (toGetFrames <= 0) return; const int framesPerBufferAlsa = 2048; toGetFrames = std::min(framesPerBufferAlsa, toGetFrames); - captureIBuff_.resize(toGetFrames * audioFormat_.nb_channels); - - if (read(captureIBuff_.data(), toGetFrames) != toGetFrames) { + if (auto r = read(toGetFrames)) { + //captureBuff_.applyGain(isCaptureMuted_ ? 0.0 : captureGain_); + //dcblocker_.process(captureBuff_); + mainRingBuffer_->put(std::move(r)); + } else RING_ERR("ALSA MIC : Couldn't read!"); - return; - } - - captureBuff_.deinterleave(captureIBuff_, audioFormat_); - captureBuff_.applyGain(isCaptureMuted_ ? 0.0 : captureGain_); - - if (audioFormat_.nb_channels != mainBufferFormat.nb_channels) { - captureBuff_.setChannelNum(mainBufferFormat.nb_channels, true); - } - if (audioFormat_.sample_rate != mainBufferFormat.sample_rate) { - int outFrames = toGetFrames * (static_cast<double>(audioFormat_.sample_rate) / mainBufferFormat.sample_rate); - AudioBuffer rsmpl_in(outFrames, mainBufferFormat); - resampler_->resample(captureBuff_, rsmpl_in); - dcblocker_.process(rsmpl_in); - mainRingBuffer_->put(rsmpl_in); - } else { - dcblocker_.process(captureBuff_); - mainRingBuffer_->put(captureBuff_); - } } void AlsaLayer::playback() { - if (!playbackHandle_) return; snd_pcm_wait(playbackHandle_, 20); - int maxFrames = 0; - + long maxFrames = 0; if (not safeUpdate(playbackHandle_, maxFrames)) return; - auto& ringBuff = getToRing(audioFormat_, maxFrames); - auto& playBuff = getToPlay(audioFormat_, maxFrames); - auto& toPlay = ringBuff.frames() > 0 ? ringBuff : playBuff; - - if (!(toPlay.frames() > 0)) - return; - - toPlay.interleave(playbackIBuff_); - write(playbackIBuff_.data(), toPlay.frames(), playbackHandle_); + if (auto toPlay = getToPlay(audioFormat_, maxFrames)) { + write(*toPlay, playbackHandle_); + } } void AlsaLayer::ringtone() @@ -756,22 +725,13 @@ void AlsaLayer::ringtone() if (!ringtoneHandle_) return; - auto file_tone = Manager::instance().getTelephoneFile(); - int ringtoneAvailFrames = 0; - + long ringtoneAvailFrames = 0; if (not safeUpdate(ringtoneHandle_, ringtoneAvailFrames)) return; - playbackBuff_.setFormat(audioFormat_); - playbackBuff_.resize(ringtoneAvailFrames); - - if (file_tone) { - RING_DBG("playback gain %.3f", playbackGain_); - file_tone->getNext(playbackBuff_, playbackGain_); + if (auto toRing = getToRing(audioFormat_, ringtoneAvailFrames)) { + write(*toRing, ringtoneHandle_); } - - playbackBuff_.interleave(playbackIBuff_); - write(playbackIBuff_.data(), ringtoneAvailFrames, ringtoneHandle_); } void AlsaLayer::updatePreference(AudioPreference &preference, int index, DeviceType type) diff --git a/src/media/audio/alsa/alsalayer.h b/src/media/audio/alsa/alsalayer.h index 795929a648268ff6b11753d5c8d3679242840cdb..4d61007843e64dbb9f4c7074f6ac6641d17cce8d 100644 --- a/src/media/audio/alsa/alsalayer.h +++ b/src/media/audio/alsa/alsalayer.h @@ -154,7 +154,7 @@ class AlsaLayer : public AudioLayer { * will often hold on to a device temporarily after it has been opened * and closed. */ - bool openDevice(snd_pcm_t **pcm, const std::string &dev, snd_pcm_stream_t stream); + bool openDevice(snd_pcm_t **pcm, const std::string &dev, snd_pcm_stream_t stream, AudioFormat& format); /** * Number of audio cards on which capture stream has been opened @@ -187,7 +187,7 @@ class AlsaLayer : public AudioLayer { void startPlaybackStream(); void preparePlaybackStream(); - bool alsa_set_params(snd_pcm_t *pcm_handle); + bool alsa_set_params(snd_pcm_t *pcm_handle, AudioFormat& format); /** * Copy a data buffer in the internal ring buffer @@ -195,7 +195,7 @@ class AlsaLayer : public AudioLayer { * @param buffer The non-interleaved data to be copied * @param frames Frames in the buffer */ - void write(AudioSample* buffer, int frames, snd_pcm_t *handle); + void write(const AudioFrame& buffer, snd_pcm_t *handle); /** * Read data from the internal ring buffer @@ -204,7 +204,7 @@ class AlsaLayer : public AudioLayer { * @param frames The number of frames to get * @return int The number of frames actually read */ - int read(AudioSample* buffer, int frames); + std::unique_ptr<AudioFrame> read(unsigned frames); virtual void updatePreference(AudioPreference &pref, int index, DeviceType type); diff --git a/src/media/audio/audio_frame_resizer.cpp b/src/media/audio/audio_frame_resizer.cpp index 429bef071570c531bac388dc6c658c6ad6f7a3d8..8766d81255dc3682c8d6712c8203e15c45ee624f 100644 --- a/src/media/audio/audio_frame_resizer.cpp +++ b/src/media/audio/audio_frame_resizer.cpp @@ -64,8 +64,8 @@ void AudioFrameResizer::setFormat(const AudioFormat& format, int size) { if (format != format_) { - if (auto discaded = samples()) - RING_WARN("Discarding %d samples", discaded); + if (auto discarded = samples()) + RING_WARN("Discarding %d samples", discarded); av_audio_fifo_free(queue_); format_ = format; queue_ = av_audio_fifo_alloc(format.sampleFormat, format.nb_channels, frameSize_); diff --git a/src/media/audio/audio_input.cpp b/src/media/audio/audio_input.cpp index 517372bf6119b1628b35abc4f133fc5ca11526ca..a3f397fec79af7b54848a8c61f18c7d35443a187 100644 --- a/src/media/audio/audio_input.cpp +++ b/src/media/audio/audio_input.cpp @@ -92,36 +92,22 @@ AudioInput::nextFromDevice() auto& mainBuffer = Manager::instance().getRingBufferPool(); auto bufferFormat = mainBuffer.getInternalAudioFormat(); - // compute number of samples contained in a frame with duration MS_PER_PACKET - const auto samplesPerPacket = MS_PER_PACKET * bufferFormat.sample_rate; - const std::size_t samplesToGet = std::chrono::duration_cast<std::chrono::seconds>(samplesPerPacket).count(); - - if (mainBuffer.availableForGet(id_) < samplesToGet - && not mainBuffer.waitForDataAvailable(id_, samplesToGet, MS_PER_PACKET)) { + if (not mainBuffer.waitForDataAvailable(id_, MS_PER_PACKET)) { return; } - // getData resets the format to internal hardware format, will have to be resampled - micData_.setFormat(bufferFormat); - micData_.resize(samplesToGet); - const auto samples = mainBuffer.getData(micData_, id_); - if (samples != samplesToGet) + auto samples = mainBuffer.getData(id_); + if (not samples) return; - if (muteState_) // audio is muted, set samples to 0 - micData_.reset(); + //if (muteState_) // audio is muted, set samples to 0 + // micData_.reset(); + // TODO handle mute - std::lock_guard<std::mutex> lk(fmtMutex_); - AudioBuffer resampled; - resampled.setFormat(format_); - if (bufferFormat != format_) { - resampler_->resample(micData_, resampled); - } else { - resampled = micData_; + { + std::lock_guard<std::mutex> lk(fmtMutex_); + resizer_->enqueue(resampler_->resample(std::move(samples), format_)); } - - auto audioFrame = resampled.toAVFrame(); - resizer_->enqueue(std::move(audioFrame)); } void @@ -145,16 +131,7 @@ AudioInput::nextFromFile() createDecoder(); break; case MediaDecoder::Status::FrameFinished: - if (inFmt != format_) { - AudioFrame out; - out.pointer()->format = format_.sampleFormat; - out.pointer()->sample_rate = format_.sample_rate; - out.pointer()->channel_layout = av_get_default_channel_layout(format_.nb_channels); - out.pointer()->channels = format_.nb_channels; - resampler_->resample(frame->pointer(), out.pointer()); - frame->copyFrom(out); - } - resizer_->enqueue(std::move(frame)); + resizer_->enqueue(resampler_->resample(std::move(frame), format_)); break; case MediaDecoder::Status::Success: default: @@ -298,9 +275,7 @@ AudioInput::setFormat(const AudioFormat& fmt) { std::lock_guard<std::mutex> lk(fmtMutex_); format_ = fmt; - frameSize_ = format_.sample_rate * MS_PER_PACKET.count() / 1000; - resizer_.reset(new AudioFrameResizer(format_, frameSize_, - [this](std::shared_ptr<AudioFrame>&& f){ frameResized(std::move(f)); })); + resizer_->setFormat(format_, format_.sample_rate * MS_PER_PACKET.count() / 1000); } void diff --git a/src/media/audio/audio_receive_thread.cpp b/src/media/audio/audio_receive_thread.cpp index 9865b5a357c0844013373606620c539f74cb7f6d..7fd31bb2c7abba68fa3319a54937427a451fd551 100644 --- a/src/media/audio/audio_receive_thread.cpp +++ b/src/media/audio/audio_receive_thread.cpp @@ -93,12 +93,13 @@ void AudioReceiveThread::process() { AudioFormat mainBuffFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat(); - auto decodedFrame = std::make_shared<AudioFrame>(); + auto decodedFrame = std::make_unique<AudioFrame>(); + auto sharedFrame = std::make_shared<AudioFrame>(); switch (audioDecoder_->decode(*decodedFrame)) { case MediaDecoder::Status::FrameFinished: - audioDecoder_->writeToRingBuffer(*decodedFrame, *ringbuffer_, - mainBuffFormat); - notify(std::static_pointer_cast<MediaFrame>(decodedFrame)); + sharedFrame->copyFrom(*decodedFrame); + audioDecoder_->writeToRingBuffer(std::move(decodedFrame), *ringbuffer_, mainBuffFormat); + notify(std::static_pointer_cast<MediaFrame>(sharedFrame)); return; case MediaDecoder::Status::DecodeError: RING_WARN("decoding failure, trying to reset decoder..."); diff --git a/src/media/audio/audio_rtp_session.cpp b/src/media/audio/audio_rtp_session.cpp index 58ad403a86280a5efb3c75dbd33df35f42cccafd..6e3326788dee82cc0c0d9de17962f48635c092fe 100644 --- a/src/media/audio/audio_rtp_session.cpp +++ b/src/media/audio/audio_rtp_session.cpp @@ -48,8 +48,6 @@ namespace ring { -constexpr static auto NEWPARAMS_TIMEOUT = std::chrono::milliseconds(1000); - AudioRtpSession::AudioRtpSession(const std::string& id) : RtpSession(id) { diff --git a/src/media/audio/audiobuffer.h b/src/media/audio/audiobuffer.h index a79f4cfe4b74524eb51454445c6a53c32c63c67d..10353a08b2d0c3fcaa246488000b3239316e4e6c 100644 --- a/src/media/audio/audiobuffer.h +++ b/src/media/audio/audiobuffer.h @@ -96,10 +96,10 @@ struct AudioFormat { } static const constexpr unsigned DEFAULT_SAMPLE_RATE = 48000; - static const AudioFormat DEFAULT() { return AudioFormat{16000, 1}; } - static const AudioFormat NONE() { return AudioFormat{0, 0}; } - static const AudioFormat MONO() { return AudioFormat{DEFAULT_SAMPLE_RATE, 1}; } - static const AudioFormat STEREO() { return AudioFormat{DEFAULT_SAMPLE_RATE, 2}; } + static const constexpr AudioFormat DEFAULT() { return AudioFormat{16000, 1}; } + static const constexpr AudioFormat NONE() { return AudioFormat{0, 0}; } + static const constexpr AudioFormat MONO() { return AudioFormat{DEFAULT_SAMPLE_RATE, 1}; } + static const constexpr AudioFormat STEREO() { return AudioFormat{DEFAULT_SAMPLE_RATE, 2}; } }; std::ostream& operator <<(std::ostream& stream, const AudioFormat& f); diff --git a/src/media/audio/audiolayer.cpp b/src/media/audio/audiolayer.cpp index 63759fbf58f6e2977b4cbe16b569ab8b54cd7cfe..82383161a88ac17f4b29c9c59f567e847d83158c 100644 --- a/src/media/audio/audiolayer.cpp +++ b/src/media/audio/audiolayer.cpp @@ -56,7 +56,7 @@ void AudioLayer::hardwareFormatAvailable(AudioFormat playback) std::lock_guard<std::mutex> lock(mutex_); RING_DBG("Hardware audio format available : %s", playback.toString().c_str()); audioFormat_ = Manager::instance().hardwareAudioFormatChanged(playback); - urgentRingBuffer_.setFormat(audioFormat_); + urgentRingBuffer_.setFormat(playback); } void AudioLayer::hardwareInputFormatAvailable(AudioFormat capture) @@ -85,7 +85,7 @@ void AudioLayer::flushUrgent() void AudioLayer::putUrgent(AudioBuffer& buffer) { std::lock_guard<std::mutex> lock(mutex_); - urgentRingBuffer_.put(buffer); + urgentRingBuffer_.put(buffer.toAVFrame()); } // Notify (with a beep) an incoming call when there is already a call in progress @@ -107,7 +107,7 @@ void AudioLayer::notifyIncomingCall() return; Tone tone("440/160", getSampleRate()); - unsigned int nbSample = tone.getSize(); + size_t nbSample = tone.getSize(); AudioBuffer buf(nbSample, AudioFormat::MONO()); tone.getNext(buf, 1.0); @@ -116,99 +116,56 @@ void AudioLayer::notifyIncomingCall() putUrgent(buf); } - -const AudioBuffer& AudioLayer::getToRing(AudioFormat format, size_t writableSamples) +std::shared_ptr<AudioFrame> +AudioLayer::getToRing(AudioFormat format, size_t writableSamples) { ringtoneBuffer_.resize(0); - auto fileToPlay = Manager::instance().getTelephoneFile(); - if (fileToPlay) { + if (auto fileToPlay = Manager::instance().getTelephoneFile()) { auto fileformat = fileToPlay->getFormat(); - bool resample = format.sample_rate != fileformat.sample_rate; + bool resample = format != fileformat; size_t readableSamples = resample - ? fileformat.sample_rate * (double) writableSamples / (double) audioFormat_.sample_rate + ? (rational<size_t>(writableSamples, audioFormat_.sample_rate) * (size_t)fileformat.sample_rate).real<size_t>() : writableSamples; ringtoneBuffer_.setFormat(fileformat); ringtoneBuffer_.resize(readableSamples); fileToPlay->getNext(ringtoneBuffer_, isRingtoneMuted_ ? 0. : 1.); - ringtoneBuffer_.setChannelNum(format.nb_channels, true); - AudioBuffer* out; - if (resample) { - ringtoneResampleBuffer_.setSampleRate(format.sample_rate); - resampler_->resample(ringtoneBuffer_, ringtoneResampleBuffer_); - out = &ringtoneResampleBuffer_; - } else { - out = &ringtoneBuffer_; - } - return *out; + return resampler_->resample(ringtoneBuffer_.toAVFrame(), format); } - return ringtoneBuffer_; + return {}; } -const AudioBuffer& AudioLayer::getToPlay(AudioFormat format, size_t writableSamples) +std::shared_ptr<AudioFrame> +AudioLayer::getToPlay(AudioFormat format, size_t writableSamples) { - playbackBuffer_.resize(0); - playbackResampleBuffer_.resize(0); - notifyIncomingCall(); + auto& bufferPool = Manager::instance().getRingBufferPool(); - size_t urgentSamples = std::min(urgentRingBuffer_.availableForGet(RingBufferPool::DEFAULT_ID), writableSamples); - - if (urgentSamples) { - playbackBuffer_.setFormat(format); - playbackBuffer_.resize(urgentSamples); - urgentRingBuffer_.get(playbackBuffer_, RingBufferPool::DEFAULT_ID); // retrive only the first sample_spec->channels channels - playbackBuffer_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_); - // Consume the regular one as well (same amount of samples) - Manager::instance().getRingBufferPool().discard(urgentSamples, RingBufferPool::DEFAULT_ID); - return playbackBuffer_; - } - - if (auto toneToPlay = Manager::instance().getTelephoneTone()) { - playbackBuffer_.setFormat(format); - playbackBuffer_.resize(writableSamples); - toneToPlay->getNext(playbackBuffer_, playbackGain_); // retrive only n_channels - return playbackBuffer_; + if (auto urgentSamples = urgentRingBuffer_.get(RingBufferPool::DEFAULT_ID)) { + bufferPool.discard(1, RingBufferPool::DEFAULT_ID); + return urgentSamples; } + // flush remaining samples in _urgentRingBuffer + flushUrgent(); - flushUrgent(); // flush remaining samples in _urgentRingBuffer - - size_t availSamples = Manager::instance().getRingBufferPool().availableForGet(RingBufferPool::DEFAULT_ID); - if (not availSamples) - return playbackBuffer_; - - // how many samples we want to read from the buffer - size_t readableSamples = writableSamples; - - AudioFormat mainBufferAudioFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat(); - - bool resample = audioFormat_.sample_rate != mainBufferAudioFormat.sample_rate; - double resampleFactor = 1.; - if (resample) { - resampleFactor = (double) audioFormat_.sample_rate / mainBufferAudioFormat.sample_rate; - readableSamples = (double) readableSamples / resampleFactor; + if (not playbackQueue_) + playbackQueue_.reset(new AudioFrameResizer(format, writableSamples)); + else + playbackQueue_->setFrameSize(writableSamples); + + std::shared_ptr<AudioFrame> playbackBuf {}; + while (!(playbackBuf = playbackQueue_->dequeue())) { + if (auto toneToPlay = Manager::instance().getTelephoneTone()) { + playbackQueue_->enqueue(resampler_->resample(toneToPlay->getNext(), format)); + } else if (auto buf = bufferPool.getData(RingBufferPool::DEFAULT_ID)) { + playbackQueue_->enqueue(resampler_->resample(std::move(buf), format)); + } else { + break; + } } - readableSamples = std::min(readableSamples, availSamples); - size_t nResampled = (double) readableSamples * resampleFactor; - - playbackBuffer_.setFormat(mainBufferAudioFormat); - playbackBuffer_.resize(readableSamples); - Manager::instance().getRingBufferPool().getData(playbackBuffer_, RingBufferPool::DEFAULT_ID); - playbackBuffer_.setChannelNum(format.nb_channels, true); - - if (resample) { - playbackResampleBuffer_.setFormat(format); - playbackResampleBuffer_.resize(nResampled); - resampler_->resample(playbackBuffer_, playbackResampleBuffer_); - playbackResampleBuffer_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_); - return playbackResampleBuffer_; - } else { - playbackBuffer_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_); - return playbackBuffer_; - } + return playbackBuf; } - } // namespace ring diff --git a/src/media/audio/audiolayer.h b/src/media/audio/audiolayer.h index 181885d49385fadfb3626dc2e0beaff7110ea732..10da826ac3a503b19033f6b8915cf71cdc2039c6 100644 --- a/src/media/audio/audiolayer.h +++ b/src/media/audio/audiolayer.h @@ -28,6 +28,7 @@ #include "ringbuffer.h" #include "dcblocker.h" #include "noncopyable.h" +#include "audio_frame_resizer.h" #include <chrono> #include <mutex> @@ -228,9 +229,15 @@ class AudioLayer { void devicesChanged(); - const AudioBuffer& getToPlay(AudioFormat format, size_t writableSamples); + std::shared_ptr<AudioFrame> getToPlay(AudioFormat format, size_t writableSamples); - const AudioBuffer& getToRing(AudioFormat format, size_t writableSamples); + std::shared_ptr<AudioFrame> getToRing(AudioFormat format, size_t writableSamples); + + std::shared_ptr<AudioFrame> getPlayback(AudioFormat format, size_t samples) { + const auto& ringBuff = getToRing(format, samples); + const auto& playBuff = getToPlay(format, samples); + return ringBuff ? ringBuff : playBuff; + } /** * True if capture is not to be used @@ -264,6 +271,7 @@ class AudioLayer { AudioBuffer playbackResampleBuffer_; AudioBuffer ringtoneBuffer_; AudioBuffer ringtoneResampleBuffer_; + std::unique_ptr<AudioFrameResizer> playbackQueue_; /** * Whether or not the audio layer stream is started diff --git a/src/media/audio/audioloop.cpp b/src/media/audio/audioloop.cpp index 395e6bf67e73c22ed53ea6af1761d172344c6dbc..9998095c98430a6505cd55066b2b1a79cf9b61fd 100644 --- a/src/media/audio/audioloop.cpp +++ b/src/media/audio/audioloop.cpp @@ -71,22 +71,28 @@ AudioLoop::getNext(AudioBuffer& output, double gain) while (total_samples != 0) { size_t samples = std::min(total_samples, buf_samples - pos); - output.copy(*buffer_, samples, pos, output_pos); - output_pos += samples; pos = (pos + samples) % buf_samples; - total_samples -= samples; } output.applyGain(gain); - pos_ = pos; - onBufferFinish(); } void AudioLoop::onBufferFinish() {} +std::unique_ptr<AudioFrame> +AudioLoop::getNext(size_t samples) +{ + if (samples == 0) { + samples = buffer_->getSampleRate() / 50; + } + AudioBuffer buff(samples, buffer_->getFormat()); + getNext(buff, 1); + return buff.toAVFrame(); +} + } // namespace ring diff --git a/src/media/audio/audioloop.h b/src/media/audio/audioloop.h index ef0b2ae13b110a73fa340845ecb553d7b149d102..eff5388d4ec380d04d2f833006a8077af3544587 100644 --- a/src/media/audio/audioloop.h +++ b/src/media/audio/audioloop.h @@ -56,6 +56,7 @@ class AudioLoop { * @param gain The gain [-1.0, 1.0] */ void getNext(AudioBuffer& output, double gain); + std::unique_ptr<AudioFrame> getNext(size_t samples = 0); void seek(double relative_position); diff --git a/src/media/audio/coreaudio/ios/corelayer.cpp b/src/media/audio/coreaudio/ios/corelayer.cpp index fe826a7b655b422af8d7f663d802d5df3d542ea2..f0b1e0ace59c50bcbcc5249aa5a18a90fe787966 100644 --- a/src/media/audio/coreaudio/ios/corelayer.cpp +++ b/src/media/audio/coreaudio/ios/corelayer.cpp @@ -156,9 +156,7 @@ CoreLayer::setupOutputBus() { &size, &outSampleRate); outputASBD.mSampleRate = outSampleRate; - - audioFormat_ = {static_cast<unsigned int>(outputASBD.mSampleRate), - static_cast<unsigned int>(outputASBD.mChannelsPerFrame)}; + outSampleRate_ = outputASBD.mSampleRate; size = sizeof(outputASBD); checkErr(AudioUnitGetProperty(ioUnit_, @@ -169,7 +167,7 @@ CoreLayer::setupOutputBus() { &size)); // Only change sample rate. - outputASBD.mSampleRate = audioFormat_.sample_rate; + outputASBD.mSampleRate = outSampleRate_; outputASBD.mFormatID = kAudioFormatLinearPCM; outputASBD.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked; @@ -184,7 +182,8 @@ CoreLayer::setupOutputBus() { &outputASBD, size)); - hardwareFormatAvailable(audioFormat_); + hardwareFormatAvailable({static_cast<unsigned int>(outputASBD.mSampleRate), + static_cast<unsigned int>(outputASBD.mChannelsPerFrame)}); } void @@ -223,13 +222,6 @@ CoreLayer::setupInputBus() { inputASBD.mFormatID = kAudioFormatLinearPCM; inputASBD.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked; - audioInputFormat_ = {static_cast<unsigned int>(inputASBD.mSampleRate), - static_cast<unsigned int>(inputASBD.mChannelsPerFrame)}; - hardwareInputFormatAvailable(audioInputFormat_); - - // Keep some values to not ask them every time the read callback is fired up - inSampleRate_ = inputASBD.mSampleRate; - inChannelsPerFrame_ = inputASBD.mChannelsPerFrame; // Set format on output *SCOPE* in input *BUS*. checkErr(AudioUnitGetProperty(ioUnit_, @@ -239,8 +231,13 @@ CoreLayer::setupInputBus() { &inputASBD, &size)); - // Keep everything else and change only sample rate (or else SPLOSION!!!) - inputASBD.mSampleRate = audioInputFormat_.sample_rate; + audioInputFormat_ = {static_cast<unsigned int>(inputASBD.mSampleRate), + static_cast<unsigned int>(inputASBD.mChannelsPerFrame)}; + hardwareInputFormatAvailable(audioInputFormat_); + + // Keep some values to not ask them every time the read callback is fired up + inSampleRate_ = inputASBD.mSampleRate; + inChannelsPerFrame_ = inputASBD.mChannelsPerFrame; size = sizeof(inputASBD); checkErr(AudioUnitSetProperty(ioUnit_, @@ -265,7 +262,7 @@ CoreLayer::setupInputBus() { AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &size, &bufferDuration); - UInt32 bufferSizeFrames = audioInputFormat_.sample_rate * bufferDuration; + UInt32 bufferSizeFrames = inSampleRate_ * bufferDuration; UInt32 bufferSizeBytes = bufferSizeFrames * sizeof(Float32); size = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * inputASBD.mChannelsPerFrame); rawBuff_.reset(new Byte[size + bufferSizeBytes * inputASBD.mChannelsPerFrame]); @@ -380,73 +377,14 @@ CoreLayer::write(AudioUnitRenderActionFlags* ioActionFlags, (void) inTimeStamp; (void) inBusNumber; - auto& manager = Manager::instance(); - auto& bufferPool = manager.getRingBufferPool(); - - auto mainBufferFormat = bufferPool.getInternalAudioFormat(); - const AudioFormat currentOutFormat = { static_cast<unsigned int>(outSampleRate_), - static_cast<unsigned int>(outChannelsPerFrame_)}; - - auto resample = currentOutFormat.sample_rate != mainBufferFormat.sample_rate; - - auto normalFramesToGet = bufferPool.availableForGet(RingBufferPool::DEFAULT_ID); - auto urgentFramesToGet = urgentRingBuffer_.availableForGet(RingBufferPool::DEFAULT_ID); - - double resampleFactor; - decltype(normalFramesToGet) readableSamples; - decltype(urgentFramesToGet) readableUrgentSamples; + AudioFormat currentOutFormat { static_cast<unsigned>(outSampleRate_), + static_cast<unsigned>(outChannelsPerFrame_), + AV_SAMPLE_FMT_FLTP}; - if (resample) { - resampleFactor = mainBufferFormat.sample_rate / static_cast<double>(currentOutFormat.sample_rate); - readableSamples = std::ceil(inNumberFrames * resampleFactor); - } else { - readableSamples = inNumberFrames; - } - - // incoming call during call - if (urgentFramesToGet > 0) { - readableUrgentSamples = std::min(readableSamples, urgentFramesToGet); - - playbackBuff_.setFormat(currentOutFormat); - playbackBuff_.resize(readableUrgentSamples); - urgentRingBuffer_.get(playbackBuff_, RingBufferPool::DEFAULT_ID); - playbackBuff_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_); - - for (unsigned i = 0; i < currentOutFormat.nb_channels; ++i) { - playbackBuff_.channelToFloat(reinterpret_cast<Float32*>(ioData->mBuffers[i].mData), i); - } - manager.getRingBufferPool().discard(readableUrgentSamples, RingBufferPool::DEFAULT_ID); - } - - if (normalFramesToGet > 0) { - readableSamples = std::min(readableSamples, normalFramesToGet); - } - - auto& ringBuff = getToRing(audioFormat_, readableSamples); - auto& playBuff = getToPlay(audioFormat_, readableSamples); - - auto& toPlay = ringBuff.frames() > 0 ? ringBuff : playBuff; - - if (toPlay.frames() == 0) { - // clear buffer - for (unsigned i = 0; i < currentOutFormat.nb_channels; ++i) { - std::fill_n(reinterpret_cast<Float32*>(ioData->mBuffers[i].mData), - ioData->mBuffers[i].mDataByteSize / sizeof(Float32), 0); - } - } else if (resample) { - // resample - playbackBuff_.setFormat(currentOutFormat); - playbackBuff_.resize(readableSamples); - resampler_->resample(toPlay, playbackBuff_); - playbackBuff_.applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_); - for (unsigned i = 0; i < audioFormat_.nb_channels; ++i) { - playbackBuff_.channelToFloat(reinterpret_cast<Float32*>(ioData->mBuffers[i].mData), i); - } - } else { - // normal play - const_cast<AudioBuffer&>(toPlay).applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_); - for (unsigned i = 0; i < audioFormat_.nb_channels; ++i) { - toPlay.channelToFloat(reinterpret_cast<Float32*>(ioData->mBuffers[i].mData), i); + if (auto toPlay = getPlayback(currentOutFormat, inNumberFrames)) { + const auto& frame = *toPlay->pointer(); + for (unsigned i = 0; i < frame.channels; ++i) { + std::copy_n((Float32*)frame.extended_data[i], inNumberFrames, (Float32*)ioData->mBuffers[i].mData); } } } @@ -485,31 +423,13 @@ CoreLayer::read(AudioUnitRenderActionFlags* ioActionFlags, inNumberFrames, captureBuff_)); - // Add them to Ring ringbuffer. - const AudioFormat mainBufferFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat(); - bool resample = inSampleRate_ != mainBufferFormat.sample_rate; - - // FIXME: Performance! There *must* be a better way. This is testing only. - auto inBuff = AudioBuffer {inNumberFrames, audioInputFormat_}; - - for (unsigned i = 0; i < inChannelsPerFrame_; ++i) { - auto data = reinterpret_cast<Float32*>(captureBuff_->mBuffers[i].mData); - for (unsigned j = 0; j < inNumberFrames; ++j) { - (*inBuff.getChannel(i))[j] = static_cast<AudioSample>(data[j] * 32768); - } - } - - if (resample) { - //FIXME: May be a multiplication, check alsa vs pulse implementation. - UInt32 outSamples = inNumberFrames * (mainBufferFormat.sample_rate / static_cast<double>(audioInputFormat_.sample_rate)); - auto out = AudioBuffer {outSamples, mainBufferFormat}; - inputResampler_->resample(inBuff, out); - dcblocker_.process(out); - mainRingBuffer_->put(out); - } else { - dcblocker_.process(inBuff); - mainRingBuffer_->put(inBuff); - } + auto format = audioInputFormat_; + format.sampleFormat = AV_SAMPLE_FMT_FLTP; + auto inBuff = std::make_unique<AudioFrame>(audioInputFormat_, inNumberFrames); + auto& in = *inBuff->pointer(); + for (unsigned i = 0; i < inChannelsPerFrame_; ++i) + std::copy_n((Float32*)captureBuff_->mBuffers[i].mData, inNumberFrames, (Float32*)in.extended_data[i]); + mainRingBuffer_->put(std::move(inBuff)); } void CoreLayer::updatePreference(AudioPreference &preference, int index, DeviceType type) diff --git a/src/media/audio/coreaudio/osx/corelayer.cpp b/src/media/audio/coreaudio/osx/corelayer.cpp index 33e47b05b8669cc6f3970c02feb7dabc0fc7ffc5..721037317a63e90b2eef39d5f44552a431a1e89b 100644 --- a/src/media/audio/coreaudio/osx/corelayer.cpp +++ b/src/media/audio/coreaudio/osx/corelayer.cpp @@ -91,7 +91,6 @@ CoreLayer::initAudioLayerIO() AudioUnitScope outputBus = 0; AudioUnitScope inputBus = 1; - UInt32 size = sizeof(UInt32); AudioComponentDescription desc = {0}; desc.componentType = kAudioUnitType_Output; // kAudioOutputUnitProperty_EnableIO is ON and read-only @@ -109,7 +108,7 @@ CoreLayer::initAudioLayerIO() // Set stream format AudioStreamBasicDescription info; - size = sizeof(info); + UInt32 size = sizeof(info); checkErr(AudioUnitGetProperty(ioUnit_, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, @@ -291,18 +290,15 @@ CoreLayer::write(AudioUnitRenderActionFlags* ioActionFlags, UInt32 inNumberFrames, AudioBufferList* ioData) { - auto& ringBuff = getToRing(audioFormat_, inNumberFrames); - auto& playBuff = getToPlay(audioFormat_, inNumberFrames); - - auto& toPlay = ringBuff.frames() > 0 ? ringBuff : playBuff; - - if (toPlay.frames() == 0) { - for (int i = 0; i < audioFormat_.nb_channels; ++i) - std::fill_n(reinterpret_cast<Float32*>(ioData->mBuffers[i].mData), - ioData->mBuffers[i].mDataByteSize/sizeof(Float32), 0); + auto format = audioFormat_; + format.sampleFormat = AV_SAMPLE_FMT_FLTP; + if (auto toPlay = getPlayback(format, inNumberFrames)) { + for (int i = 0; i < format.nb_channels; ++i) { + std::copy_n((Float32*)toPlay->pointer()->extended_data[i], inNumberFrames, (Float32*)ioData->mBuffers[i].mData); + } } else { - for (int i = 0; i < audioFormat_.nb_channels; ++i) - toPlay.channelToFloat(reinterpret_cast<Float32*>(ioData->mBuffers[i].mData), i); + for (int i = 0; i < format.nb_channels; ++i) + std::fill_n(reinterpret_cast<Float32*>(ioData->mBuffers[i].mData), inNumberFrames, 0); } } @@ -339,34 +335,13 @@ CoreLayer::read(AudioUnitRenderActionFlags* ioActionFlags, inNumberFrames, captureBuff_)); - // Add them to Ring ringbuffer. - const AudioFormat mainBufferFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat(); - bool resample = inSampleRate_ != mainBufferFormat.sample_rate; - - // FIXME: Performance! There *must* be a better way. This is testing only. - auto inBuff = AudioBuffer {inNumberFrames, audioInputFormat_}; - - for (int i = 0; i < inChannelsPerFrame_; ++i) { - auto data = reinterpret_cast<Float32*>(captureBuff_->mBuffers[i].mData); - for (int j = 0; j < inNumberFrames; ++j) { - (*inBuff.getChannel(i))[j] = static_cast<AudioSample>(data[j] / .000030517578125f); - } - } - - if (resample) { - //RING_WARN("Resampling Input."); - - //FIXME: May be a multiplication, check alsa vs pulse implementation. - - UInt32 outSamples = inNumberFrames / (static_cast<double>(audioInputFormat_.sample_rate) / mainBufferFormat.sample_rate); - auto out = AudioBuffer {outSamples, mainBufferFormat}; - inputResampler_->resample(inBuff, out); - dcblocker_.process(out); - mainRingBuffer_->put(out); - } else { - dcblocker_.process(inBuff); - mainRingBuffer_->put(inBuff); - } + auto format = audioInputFormat_; + audioInputFormat_.sampleFormat = AV_SAMPLE_FMT_FLTP; + auto inBuff = std::make_unique<AudioFrame>(audioInputFormat_, inNumberFrames); + auto& in = *inBuff->pointer(); + for (unsigned i = 0; i < inChannelsPerFrame_; ++i) + std::copy_n((Float32*)captureBuff_->mBuffers[i].mData, inNumberFrames, (Float32*)in.extended_data[i]); + mainRingBuffer_->put(std::move(inBuff)); } void CoreLayer::updatePreference(AudioPreference &preference, int index, DeviceType type) diff --git a/src/media/audio/jack/jacklayer.cpp b/src/media/audio/jack/jacklayer.cpp index 50f862001780c82829d6ba9b97f27393dd10a749..78a97d24f47d7e8390cbe8f5fc0e9a1d3374f603 100644 --- a/src/media/audio/jack/jacklayer.cpp +++ b/src/media/audio/jack/jacklayer.cpp @@ -23,8 +23,7 @@ #endif #include "jacklayer.h" -#include <cassert> -#include <climits> + #include "logger.h" #include "audio/resampler.h" #include "audio/ringbufferpool.h" @@ -35,6 +34,9 @@ #include <unistd.h> +#include <cassert> +#include <climits> + /* TODO * implement shutdown callback * auto connect optional @@ -48,6 +50,8 @@ void connectPorts(jack_client_t *client, int portType, const std::vector<jack_po { const char **physical_ports = jack_get_ports(client, NULL, NULL, portType | JackPortIsPhysical); for (unsigned i = 0; physical_ports[i]; ++i) { + if (i >= ports.size()) + break; const char *port = jack_port_name(ports[i]); if (portType & JackPortIsInput) { if (jack_connect(client, port, physical_ports[i])) { @@ -61,7 +65,7 @@ void connectPorts(jack_client_t *client, int portType, const std::vector<jack_po } } } - free(physical_ports); + jack_free(physical_ports); } bool ringbuffer_ready_for_read(const jack_ringbuffer_t *rb) @@ -71,167 +75,68 @@ bool ringbuffer_ready_for_read(const jack_ringbuffer_t *rb) } } -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); -} - -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_); - auto tone = Manager::instance().getTelephoneTone(); - auto 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(); - } -} - void JackLayer::playback() { notifyIncomingCall(); - - const size_t samplesToGet = Manager::instance().getRingBufferPool().availableForGet(RingBufferPool::DEFAULT_ID); - const size_t urgentSamplesToGet = urgentRingBuffer_.availableForGet(RingBufferPool::DEFAULT_ID); - - if (urgentSamplesToGet > 0) { - fillWithUrgent(playbackBuffer_, urgentSamplesToGet); - } else { - if (samplesToGet > 0) { - fillWithVoice(playbackBuffer_, samplesToGet); - } else { - fillWithToneOrRingtone(playbackBuffer_); - } + auto format = audioFormat_; + format.sampleFormat = AV_SAMPLE_FMT_FLTP; + if (auto toPlay = getPlayback(format, writeSpace())) { + write(*toPlay); } - - playbackFloatBuffer_.resize(playbackBuffer_.frames()); - write(playbackBuffer_, playbackFloatBuffer_); } void JackLayer::capture() { - // get audio from jack ringbuffer - read(captureBuffer_); - - const AudioFormat mainBufferFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat(); - const bool resample = mainBufferFormat.sample_rate != audioFormat_.sample_rate; - - captureBuffer_.applyGain(isCaptureMuted_ ? 0.0 : captureGain_); - - if (resample) { - int outSamples = captureBuffer_.frames() * (static_cast<double>(audioFormat_.sample_rate) / mainBufferFormat.sample_rate); - AudioBuffer out(outSamples, mainBufferFormat); - resampler_->resample(captureBuffer_, out); - dcblocker_.process(out); - mainRingBuffer_->put(out); - } else { - dcblocker_.process(captureBuffer_); - mainRingBuffer_->put(captureBuffer_); - } -} - -static void -convertToFloat(const std::vector<AudioSample> &src, std::vector<float> &dest) -{ - static const float INV_SHORT_MAX = 1 / (float) SHRT_MAX; - if (dest.size() != src.size()) { - RING_ERR("MISMATCH"); - return; - } - for (size_t i = 0; i < dest.size(); ++i) - dest[i] = src[i] * INV_SHORT_MAX; + if (auto buf = read()) + mainRingBuffer_->put(std::move(buf)); } -static void -convertFromFloat(std::vector<float> &src, std::vector<AudioSample> &dest) +size_t +JackLayer::writeSpace() { - if (dest.size() != src.size()) { - RING_ERR("MISMATCH"); - return; + if (out_ringbuffers_.empty()) + return 0; + size_t toWrite {std::numeric_limits<size_t>::max()}; + for (unsigned i = 0; i < out_ringbuffers_.size(); ++i) { + toWrite = std::min(toWrite, jack_ringbuffer_write_space(out_ringbuffers_[i])); } - for (size_t i = 0; i < dest.size(); ++i) - dest[i] = src[i] * SHRT_MAX; + return std::min<size_t>(toWrite / sizeof(float), audioFormat_.sample_rate / 25); } void -JackLayer::write(AudioBuffer &buffer, std::vector<float> &floatBuffer) +JackLayer::write(const AudioFrame& buffer) { - for (unsigned i = 0; i < out_ringbuffers_.size(); ++i) { - const unsigned inChannel = std::min(i, buffer.channels() - 1); - convertToFloat(*buffer.getChannel(inChannel), floatBuffer); - - // write to output - const size_t to_ringbuffer = jack_ringbuffer_write_space(out_ringbuffers_[i]); - const size_t write_bytes = std::min(buffer.frames() * sizeof(floatBuffer[0]), to_ringbuffer); - // FIXME: while we have samples to write AND while we have space to write them - const size_t written_bytes = jack_ringbuffer_write(out_ringbuffers_[i], - (const char *) floatBuffer.data(), write_bytes); - if (written_bytes < write_bytes) - RING_WARN("Dropped %zu bytes for channel %u", write_bytes - written_bytes, i); + auto num_samples = buffer.pointer()->nb_samples; + auto num_bytes = num_samples * sizeof(float); + auto channels = std::min<size_t>(out_ringbuffers_.size(), buffer.pointer()->channels); + for (size_t i = 0; i < channels; ++i) { + jack_ringbuffer_write(out_ringbuffers_[i], (const char*)buffer.pointer()->extended_data[i], num_bytes); } } -void -JackLayer::read(AudioBuffer &buffer) +std::unique_ptr<AudioFrame> +JackLayer::read() { - 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; + if (in_ringbuffers_.empty()) + return {}; - captureFloatBuffer_.resize(incomingSamples); - buffer.resize(incomingSamples); + size_t toRead {std::numeric_limits<size_t>::max()}; + for (unsigned i = 0; i < in_ringbuffers_.size(); ++i) { + toRead = std::min(toRead, jack_ringbuffer_read_space(in_ringbuffers_[i])); + } + if (not toRead) + return {}; - // 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; - } + auto format = audioInputFormat_; + format.sampleFormat = AV_SAMPLE_FMT_FLTP; + auto buffer = std::make_unique<AudioFrame>(format, toRead / sizeof(jack_default_audio_sample_t)); - /* 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)); + for (unsigned i = 0; i < in_ringbuffers_.size(); ++i) { + jack_ringbuffer_read(in_ringbuffers_[i], (char *) buffer->pointer()->extended_data[i], toRead); } + return buffer; } /* This thread can lock, do whatever it wants, and read from/write to the jack @@ -262,8 +167,6 @@ JackLayer::ringbuffer_worker() // is rather arbitrary. We should wait until ring has/needs data // and jack has/needs data. data_ready_.wait(lock, [&] { - // Note: lock is released while waiting, and held when woken - // up, so this predicate is called while holding the lock return status_ != Status::Started or ringbuffer_ready_for_read(in_ringbuffers_[0]); }); @@ -274,10 +177,11 @@ void createPorts(jack_client_t *client, std::vector<jack_port_t *> &ports, bool playback, std::vector<jack_ringbuffer_t *> &ringbuffers) { - const char **physical_ports = jack_get_ports(client, NULL, NULL, playback ? JackPortIsInput : JackPortIsOutput | JackPortIsPhysical); for (unsigned i = 0; physical_ports[i]; ++i) { + if (i == 2) + break; char port_name[32] = {0}; if (playback) snprintf(port_name, sizeof(port_name), "out_%d", i + 1); @@ -298,7 +202,7 @@ createPorts(jack_client_t *client, std::vector<jack_port_t *> &ports, throw std::runtime_error("Could not lock JACK ringbuffer in memory"); ringbuffers.push_back(rb); } - free(physical_ports); + jack_free(physical_ports); } @@ -306,19 +210,6 @@ JackLayer::JackLayer(const AudioPreference &p) : AudioLayer(p), captureClient_(nullptr), playbackClient_(nullptr), - out_ports_(), - in_ports_(), - out_ringbuffers_(), - in_ringbuffers_(), - ringbuffer_thread_(), - //workerAlive_(false), - ringbuffer_thread_mutex_(), - data_ready_(), - playbackBuffer_(0, audioFormat_), - playbackFloatBuffer_(), - captureBuffer_(0, audioFormat_), - captureFloatBuffer_(), - hardwareBufferSize_(0), mainRingBuffer_(Manager::instance().getRingBufferPool().getRingBuffer(RingBufferPool::DEFAULT_ID)) { playbackClient_ = jack_client_open(PACKAGE_NAME, @@ -339,20 +230,10 @@ JackLayer::JackLayer(const AudioPreference &p) : const auto playRate = jack_get_sample_rate(playbackClient_); const auto captureRate = jack_get_sample_rate(captureClient_); - if (playRate != captureRate) - RING_ERR("Mismatch between capture rate %u and playback rate %u", playRate, captureRate); - - hardwareBufferSize_ = jack_get_buffer_size(playbackClient_); - - auto update_buffer = [] (AudioBuffer &buf, size_t size, unsigned rate, unsigned nbChannels) { - buf.setSampleRate(rate); - buf.resize(size); - buf.setChannelNum(nbChannels); - }; - - update_buffer(playbackBuffer_, hardwareBufferSize_, playRate, out_ports_.size()); - update_buffer(captureBuffer_, hardwareBufferSize_, captureRate, in_ports_.size()); + audioInputFormat_ = {captureRate, in_ringbuffers_.size()}; + hardwareFormatAvailable(AudioFormat(playRate, out_ringbuffers_.size())); + hardwareInputFormatAvailable(audioInputFormat_); jack_on_shutdown(playbackClient_, onShutdown, this); } @@ -476,15 +357,11 @@ JackLayer::startStream() } dcblocker_.reset(); - const auto hardwareFormat = AudioFormat(playbackBuffer_.getSampleRate(), out_ports_.size()); - hardwareFormatAvailable(hardwareFormat); - if (jack_activate(playbackClient_) or jack_activate(captureClient_)) { RING_ERR("Could not activate JACK client"); return; } ringbuffer_thread_ = std::thread(&JackLayer::ringbuffer_worker, this); - connectPorts(playbackClient_, JackPortIsInput, out_ports_); connectPorts(captureClient_, JackPortIsOutput, in_ports_); } diff --git a/src/media/audio/jack/jacklayer.h b/src/media/audio/jack/jacklayer.h index 6c3e0795e97bd33e38181c3b4a1722fd7077b65d..c8167a2830692f9c20967e24ed849248f2d3e0ec 100644 --- a/src/media/audio/jack/jacklayer.h +++ b/src/media/audio/jack/jacklayer.h @@ -1,35 +1,36 @@ /* - * Copyright (C) 2014-2018 Savoir-faire Linux Inc. - * - * Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef JACK_LAYER_H_ -#define JACK_LAYER_H_ +* Copyright (C) 2014-2018 Savoir-faire Linux Inc. +* +* Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com> +* Adrien Beraud <adrien.beraud@savoirfairelinux.com> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#pragma once + +#include "noncopyable.h" +#include "audio/audiolayer.h" #include <jack/jack.h> #include <jack/ringbuffer.h> + #include <thread> #include <mutex> #include <vector> #include <condition_variable> -#include "noncopyable.h" -#include "audio/audiolayer.h" - #include <memory> namespace ring { @@ -37,69 +38,55 @@ namespace ring { class RingBuffer; class JackLayer : public AudioLayer { - - private: - NON_COPYABLE(JackLayer); - jack_client_t *captureClient_; - jack_client_t *playbackClient_; - std::vector<jack_port_t *> out_ports_; - std::vector<jack_port_t *> in_ports_; - std::vector<jack_ringbuffer_t *> out_ringbuffers_; - std::vector<jack_ringbuffer_t *> in_ringbuffers_; - std::thread ringbuffer_thread_; - std::mutex ringbuffer_thread_mutex_; - std::condition_variable data_ready_; - AudioBuffer playbackBuffer_; - std::vector<float> playbackFloatBuffer_; - AudioBuffer captureBuffer_; - std::vector<float> captureFloatBuffer_; - size_t hardwareBufferSize_; - std::shared_ptr<RingBuffer> mainRingBuffer_; - - static int process_capture(jack_nframes_t frames, void *arg); - static int process_playback(jack_nframes_t frames, void *arg); - - // separate thread - void ringbuffer_worker(); - // called from ringbuffer_worker() - void playback(); - void capture(); - void fillWithUrgent(AudioBuffer &buffer, size_t samplesToGet); - void fillWithVoice(AudioBuffer &buffer, size_t samplesAvail); - void fillWithToneOrRingtone(AudioBuffer &buffer); - - void read(AudioBuffer &buffer); - void write(AudioBuffer &buffer, std::vector<float> &floatBuffer); - - - std::vector<std::string> getCaptureDeviceList() const; - std::vector<std::string> getPlaybackDeviceList() const; - - int getAudioDeviceIndex(const std::string& name, DeviceType type) const; - std::string getAudioDeviceName(int index, DeviceType type) const; - int getIndexCapture() const; - int getIndexPlayback() const; - int getIndexRingtone() const; - void updatePreference(AudioPreference &pref, int index, DeviceType type); - - /** - * Start the capture and playback. - */ - void startStream(); - - /** - * Stop playback and capture. - */ - void stopStream(); - - static void onShutdown(void *data); - - public: - - JackLayer(const AudioPreference &); - ~JackLayer(); +private: + NON_COPYABLE(JackLayer); + jack_client_t *captureClient_; + jack_client_t *playbackClient_; + std::vector<jack_port_t *> out_ports_; + std::vector<jack_port_t *> in_ports_; + std::vector<jack_ringbuffer_t *> out_ringbuffers_; + std::vector<jack_ringbuffer_t *> in_ringbuffers_; + std::thread ringbuffer_thread_; + std::mutex ringbuffer_thread_mutex_; + std::condition_variable data_ready_; + std::shared_ptr<RingBuffer> mainRingBuffer_; + + static int process_capture(jack_nframes_t frames, void *arg); + static int process_playback(jack_nframes_t frames, void *arg); + + void ringbuffer_worker(); + void playback(); + void capture(); + + std::unique_ptr<AudioFrame> read(); + void write(const AudioFrame& buffer); + size_t writeSpace(); + + std::vector<std::string> getCaptureDeviceList() const; + std::vector<std::string> getPlaybackDeviceList() const; + + int getAudioDeviceIndex(const std::string& name, DeviceType type) const; + std::string getAudioDeviceName(int index, DeviceType type) const; + int getIndexCapture() const; + int getIndexPlayback() const; + int getIndexRingtone() const; + void updatePreference(AudioPreference &pref, int index, DeviceType type); + + /** + * Start the capture and playback. + */ + void startStream(); + + /** + * Stop playback and capture. + */ + void stopStream(); + + static void onShutdown(void *data); + +public: + JackLayer(const AudioPreference &); + ~JackLayer(); }; } - -#endif // JACK_LAYER_H_ diff --git a/src/media/audio/opensl/opensllayer.cpp b/src/media/audio/opensl/opensllayer.cpp index 51e0283c579e29bbd0b6d60e2be9ff5e0acd6ac9..913c3b063fe006839091058cdcd31803ad02157e 100644 --- a/src/media/audio/opensl/opensllayer.cpp +++ b/src/media/audio/opensl/opensllayer.cpp @@ -215,9 +215,9 @@ OpenSLLayer::engineServicePlay(bool waiting) { } sample_buf* buf; while (player_ and freePlayBufQueue_.front(&buf)) { - const AudioBuffer& dat = getToPlay(hardwareFormat_, hardwareBuffSize_); - if (dat.frames() != 0) { - buf->size_ = dat.interleave((AudioSample*)buf->buf_) * sizeof(AudioSample); + if (auto dat = getToPlay(hardwareFormat_, hardwareBuffSize_)) { + buf->size_ = dat->pointer()->nb_samples * dat->pointer()->channels * sizeof(AudioSample); + std::copy_n((const AudioSample*)dat->pointer()->data[0], dat->pointer()->nb_samples, (AudioSample*)buf->buf_); if (!playBufQueue_.push(buf)) { RING_WARN("playThread player_ PLAY_KICKSTART_BUFFER_COUNT 1"); break; @@ -237,9 +237,9 @@ OpenSLLayer::engineServiceRing(bool waiting) { sample_buf* buf; while (ringtone_ and freeRingBufQueue_.front(&buf)) { freeRingBufQueue_.pop(); - const AudioBuffer& dat = getToRing(hardwareFormat_, hardwareBuffSize_); - if (dat.frames() != 0) { - buf->size_ = dat.interleave((AudioSample*)buf->buf_) * sizeof(AudioSample); + if (auto dat = getToRing(hardwareFormat_, hardwareBuffSize_)) { + buf->size_ = dat->pointer()->nb_samples * dat->pointer()->channels * sizeof(AudioSample); + std::copy_n((const AudioSample*)dat->pointer()->data[0], dat->pointer()->nb_samples, (AudioSample*)buf->buf_); if (!ringBufQueue_.push(buf)) { RING_WARN("playThread ringtone_ PLAY_KICKSTART_BUFFER_COUNT 1"); freeRingBufQueue_.push(buf); @@ -348,8 +348,10 @@ OpenSLLayer::startAudioCapture() break; recBufQueue_.pop(); if (buf->size_ > 0) { - AudioBuffer dat {(const AudioSample*)buf->buf_, buf->size_ / hardwareFormat_.getBytesPerFrame(), hardwareFormat_}; - audioCaptureFillBuffer(dat); + auto nb_samples = buf->size_ / hardwareFormat_.getBytesPerFrame(); + auto out = std::make_unique<AudioFrame>(hardwareFormat_, nb_samples); + std::copy_n((const AudioSample*)buf->buf_, nb_samples, (AudioSample*)out->pointer()->data[0]); + audioCaptureFillBuffer(std::move(out)); } buf->size_ = 0; freeRecBufQueue_.push(buf); @@ -474,24 +476,13 @@ void OpenSLLayer::updatePreference(AudioPreference& /*preference*/, int /*index*/, DeviceType /*type*/) {} -void OpenSLLayer::audioCaptureFillBuffer(AudioBuffer &buffer) +void OpenSLLayer::audioCaptureFillBuffer(std::unique_ptr<AudioFrame>&& frame) { RingBufferPool &mbuffer = Manager::instance().getRingBufferPool(); - const AudioFormat mainBufferFormat = mbuffer.getInternalAudioFormat(); - const bool resample = mainBufferFormat.sample_rate != audioFormat_.sample_rate; - - buffer.applyGain(isCaptureMuted_ ? 0.0 : captureGain_); - - if (resample) { - int outSamples = buffer.frames() * (static_cast<double>(audioFormat_.sample_rate) / mainBufferFormat.sample_rate); - AudioBuffer out(outSamples, mainBufferFormat); - resampler_->resample(buffer, out); - dcblocker_.process(out); - mainRingBuffer_->put(out); - } else { - dcblocker_.process(buffer); - mainRingBuffer_->put(buffer); - } + + // buffer.applyGain(isCaptureMuted_ ? 0.0 : captureGain_); + // dcblocker_.process(buffer); + mainRingBuffer_->put(resampler_->resample(std::move(frame), mbuffer.getInternalAudioFormat())); } void dumpAvailableEngineInterfaces() diff --git a/src/media/audio/opensl/opensllayer.h b/src/media/audio/opensl/opensllayer.h index 03da9ca85dc2129faffe89a119f53a732fb0ca95..d45c7ff5e36d287036b551db60c042abf854795d 100644 --- a/src/media/audio/opensl/opensllayer.h +++ b/src/media/audio/opensl/opensllayer.h @@ -118,7 +118,7 @@ class OpenSLLayer : public AudioLayer { void engineServiceRec(bool waiting); private: - void audioCaptureFillBuffer(AudioBuffer &buffer); + void audioCaptureFillBuffer(std::unique_ptr<AudioFrame>&& buffer); /** * Get the index of the audio card for capture diff --git a/src/media/audio/portaudio/portaudiolayer.cpp b/src/media/audio/portaudio/portaudiolayer.cpp index 5bb64c257bf51c60d3004fb7bbcdb8c9a0d9e699..52c350f536dd2af5c4035cdf7fa23e24a94794d7 100644 --- a/src/media/audio/portaudio/portaudiolayer.cpp +++ b/src/media/audio/portaudio/portaudiolayer.cpp @@ -268,71 +268,13 @@ PortAudioLayer::PortAudioLayerImpl::paOutputCallback(PortAudioLayer& parent, (void) timeInfo; (void) statusFlags; - auto& manager = Manager::instance(); - auto& buffer_pool = manager.getRingBufferPool(); - - auto mainbuffer_format = buffer_pool.getInternalAudioFormat(); - auto layer_format = parent.audioFormat_; - auto resample = layer_format.sample_rate != mainbuffer_format.sample_rate; - - auto urgentFramesToGet = parent.urgentRingBuffer_.availableForGet(RingBufferPool::DEFAULT_ID); - if (urgentFramesToGet > 0) { - RING_WARN("Getting urgent frames"); - auto totSample = std::min(framesPerBuffer, (unsigned long)urgentFramesToGet); - - playbackBuff_.setFormat(layer_format); - playbackBuff_.resize(totSample); - parent.urgentRingBuffer_.get(playbackBuff_, RingBufferPool::DEFAULT_ID); - - playbackBuff_.applyGain(parent.isPlaybackMuted_ ? 0.0 : parent.playbackGain_); - playbackBuff_.interleave(outputBuffer); - - manager.getRingBufferPool().discard(totSample, RingBufferPool::DEFAULT_ID); - } - - auto normalFramesToGet = buffer_pool.availableForGet(RingBufferPool::DEFAULT_ID); - if (normalFramesToGet > 0) { - double resampleFactor; - decltype(normalFramesToGet) readableSamples; - - if (resample) { - resampleFactor = static_cast<double>(layer_format.sample_rate) / mainbuffer_format.sample_rate; - readableSamples = std::ceil(framesPerBuffer / resampleFactor); - } else { - resampleFactor = 1.0; - readableSamples = framesPerBuffer; - } - readableSamples = std::min(readableSamples, normalFramesToGet); - - playbackBuff_.setFormat(parent.audioFormat_); - playbackBuff_.resize(readableSamples); - buffer_pool.getData(playbackBuff_, RingBufferPool::DEFAULT_ID); - playbackBuff_.applyGain(parent.isPlaybackMuted_ ? 0.0 : parent.playbackGain_); - - if (resample) { - AudioBuffer resampledOutput(readableSamples, parent.audioFormat_); - parent.resampler_->resample(playbackBuff_, resampledOutput); - - resampledOutput.interleave(outputBuffer); - } else { - playbackBuff_.interleave(outputBuffer); - } - } else { - auto tone = manager.getTelephoneTone(); - auto file_tone = manager.getTelephoneFile(); + const auto& ringBuff = parent.getToRing(parent.audioFormat_, framesPerBuffer); + const auto& playBuff = parent.getToPlay(parent.audioFormat_, framesPerBuffer); + auto toPlay = ringBuff ? ringBuff : playBuff; + if (!toPlay) + return paContinue; - playbackBuff_.setFormat(parent.audioFormat_); - playbackBuff_.resize(framesPerBuffer); - - if (tone) { - tone->getNext(playbackBuff_, parent.playbackGain_); - } else if (file_tone) { - file_tone->getNext(playbackBuff_, parent.playbackGain_); - } else { - playbackBuff_.reset(); - } - playbackBuff_.interleave(outputBuffer); - } + std::copy_n((AudioSample*)toPlay->pointer()->extended_data[0], toPlay->pointer()->nb_samples, outputBuffer); return paContinue; } @@ -355,25 +297,10 @@ PortAudioLayer::PortAudioLayerImpl::paInputCallback(PortAudioLayer& parent, return paContinue; } - const auto mainBufferFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat(); - bool resample = parent.audioInputFormat_.sample_rate != mainBufferFormat.sample_rate; - AudioBuffer inBuff(framesPerBuffer, parent.audioInputFormat_); - - inBuff.deinterleave(inputBuffer, framesPerBuffer, parent.audioInputFormat_.nb_channels); - - inBuff.applyGain(parent.isCaptureMuted_ ? 0.0 : parent.captureGain_); - - if (resample) { - auto sample_factor = static_cast<double>(parent.audioInputFormat_.sample_rate) / mainBufferFormat.sample_rate; - auto outSamples = framesPerBuffer / sample_factor; - AudioBuffer out(outSamples, mainBufferFormat); - parent.inputResampler_->resample(inBuff, out); - parent.dcblocker_.process(out); - mainRingBuffer_->put(out); - } else { - parent.dcblocker_.process(inBuff); - mainRingBuffer_->put(inBuff); - } + auto inBuff = std::make_unique<AudioFrame>(parent.audioInputFormat_, framesPerBuffer); + std::copy_n(inputBuffer, framesPerBuffer, (AudioSample*)inBuff->pointer()->extended_data[0]); + //inBuff.applyGain(parent.isCaptureMuted_ ? 0.0 : parent.captureGain_); + mainRingBuffer_->put(std::move(inBuff)); return paContinue; } diff --git a/src/media/audio/pulseaudio/pulselayer.cpp b/src/media/audio/pulseaudio/pulselayer.cpp index 83b4ae660f42f9db1582324dd910e42b7195f0b5..f248818a523a7250d44af07e72a6862d28da3882 100644 --- a/src/media/audio/pulseaudio/pulselayer.cpp +++ b/src/media/audio/pulseaudio/pulselayer.cpp @@ -26,7 +26,6 @@ #include "pulselayer.h" #include "audio/resampler.h" #include "audio/dcblocker.h" -#include "audio/resampler.h" #include "audio/ringbufferpool.h" #include "audio/ringbuffer.h" #include "logger.h" @@ -38,6 +37,7 @@ #include <unistd.h> #include <cstdlib> #include <fstream> +#include <cstring> // Std-C++11 regex feature implemented only since GCC 4.9 // Using pcre library as replacement @@ -435,15 +435,15 @@ void PulseLayer::writeToSpeaker() if (writableBytes == 0) return; - auto& buff = getToPlay(playback_->format(), writableBytes / playback_->frameSize()); + const auto& buff = getToPlay(playback_->format(), writableBytes / playback_->frameSize()); AudioSample* data = nullptr; pa_stream_begin_write(playback_->stream(), (void**)&data, &writableBytes); - if (buff.frames() == 0) + if (!buff) memset(data, 0, writableBytes); else - buff.interleave(data); + std::memcpy(data, buff->pointer()->data[0], buff->pointer()->nb_samples * playback_->frameSize()); pa_stream_write(playback_->stream(), data, writableBytes, nullptr, 0, PA_SEEK_RELATIVE); } @@ -458,37 +458,22 @@ void PulseLayer::readFromMic() if (pa_stream_peek(record_->stream() , (const void**) &data , &bytes) < 0 or !data) return; + if (bytes == 0) + return; + size_t sample_size = record_->frameSize(); - const AudioFormat format = record_->format(); - assert(format.nb_channels); - assert(sample_size); const size_t samples = bytes / sample_size; - micBuffer_.setFormat(format); - micBuffer_.resize(samples); - micBuffer_.deinterleave((AudioSample*)data, samples, format.nb_channels); - micBuffer_.applyGain(isCaptureMuted_ ? 0.0 : captureGain_); - - auto mainBufferAudioFormat = Manager::instance().getRingBufferPool().getInternalAudioFormat(); - bool resample = format.sample_rate != mainBufferAudioFormat.sample_rate; - - AudioBuffer* out; - if (resample) { - micResampleBuffer_.setSampleRate(mainBufferAudioFormat.sample_rate); - resampler_->resample(micBuffer_, micResampleBuffer_); - out = &micResampleBuffer_; - } else { - out = &micBuffer_; - } - - dcblocker_.process(*out); - out->applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_); - mainRingBuffer_->put(*out); + auto out = std::make_unique<AudioFrame>(record_->format(), samples); + std::memcpy(out->pointer()->data[0], data, bytes); if (pa_stream_drop(record_->stream()) < 0) RING_ERR("Capture stream drop failed: %s" , pa_strerror(pa_context_errno(context_))); -} + //dcblocker_.process(*out); + //out->applyGain(isPlaybackMuted_ ? 0.0 : playbackGain_); + mainRingBuffer_->put(std::move(out)); +} void PulseLayer::ringtoneToSpeaker() { @@ -499,15 +484,15 @@ void PulseLayer::ringtoneToSpeaker() if (bytes == 0) return; - auto& buff = getToRing(ringtone_->format(), bytes / ringtone_->frameSize()); + const auto& buff = getToRing(ringtone_->format(), bytes / ringtone_->frameSize()); AudioSample* data; pa_stream_begin_write(ringtone_->stream(), (void**)&data, &bytes); - if (buff.frames() == 0) + if (!buff) memset(data, 0, bytes); else - buff.interleave(data); + std::memcpy(data, buff->pointer()->data[0], buff->pointer()->nb_samples * playback_->frameSize()); pa_stream_write(ringtone_->stream(), data, bytes, nullptr, 0, PA_SEEK_RELATIVE); } diff --git a/src/media/audio/ringbuffer.cpp b/src/media/audio/ringbuffer.cpp index e21415f54c5e699b66a32a37b7d4a2f72a445ed1..137549275baad38207fa90629b7c29a468889cf4 100644 --- a/src/media/audio/ringbuffer.cpp +++ b/src/media/audio/ringbuffer.cpp @@ -26,8 +26,10 @@ #include "ringbuffer.h" #include "logger.h" +#include "media_buffer.h" +#include "libav_deps.h" + #include <chrono> -#include <utility> // for std::pair #include <cstdlib> #include <cstring> #include <algorithm> @@ -37,15 +39,16 @@ namespace ring { // corresponds to 160 ms (about 5 rtp packets) static const size_t MIN_BUFFER_SIZE = 1024; -// Create a ring buffer with 'size' bytes -RingBuffer::RingBuffer(const std::string& rbuf_id, size_t size, - AudioFormat format /* = MONO */) +RingBuffer::RingBuffer(const std::string& rbuf_id, size_t size, AudioFormat format) : id(rbuf_id) , endPos_(0) - , buffer_(std::max(size, MIN_BUFFER_SIZE), format) , lock_() , not_empty_() , readoffsets_() + , format_(format) + , resizer_(format_, format_.sample_rate / 50, [this](std::shared_ptr<AudioFrame>&& frame){ + putToBuffer(std::move(frame)); + }) {} void @@ -54,29 +57,26 @@ RingBuffer::flush(const std::string &call_id) storeReadOffset(endPos_, call_id); } - void RingBuffer::flushAll() { - ReadOffset::iterator iter; - - for (iter = readoffsets_.begin(); iter != readoffsets_.end(); ++iter) - iter->second = endPos_; + for (auto& offset : readoffsets_) + offset.second.offset = endPos_; } size_t RingBuffer::putLength() const { - const size_t buffer_size = buffer_.frames(); + const size_t buffer_size = buffer_.size(); if (buffer_size == 0) return 0; - const size_t startPos = (not readoffsets_.empty()) ? getSmallestReadOffset() : 0; + const size_t startPos = getSmallestReadOffset(); return (endPos_ + buffer_size - startPos) % buffer_size; } size_t RingBuffer::getLength(const std::string &call_id) const { - const size_t buffer_size = buffer_.frames(); + const size_t buffer_size = buffer_.size(); if (buffer_size == 0) return 0; return (endPos_ + buffer_size - getReadOffset(call_id)) % buffer_size; @@ -85,13 +85,13 @@ size_t RingBuffer::getLength(const std::string &call_id) const void RingBuffer::debug() { - RING_DBG("Start=%zu; End=%zu; BufferSize=%zu", getSmallestReadOffset(), endPos_, buffer_.frames()); + RING_DBG("Start=%zu; End=%zu; BufferSize=%zu", getSmallestReadOffset(), endPos_, buffer_.size()); } size_t RingBuffer::getReadOffset(const std::string &call_id) const { - ReadOffset::const_iterator iter = readoffsets_.find(call_id); - return (iter != readoffsets_.end()) ? iter->second : 0; + auto iter = readoffsets_.find(call_id); + return (iter != readoffsets_.end()) ? iter->second.offset : 0; } size_t @@ -99,30 +99,29 @@ RingBuffer::getSmallestReadOffset() const { if (hasNoReadOffsets()) return 0; - size_t smallest = buffer_.frames(); + size_t smallest = buffer_.size(); for(auto const& iter : readoffsets_) - smallest = std::min(smallest, iter.second); + smallest = std::min(smallest, iter.second.offset); return smallest; } void RingBuffer::storeReadOffset(size_t offset, const std::string &call_id) { - ReadOffset::iterator iter = readoffsets_.find(call_id); + ReadOffsetMap::iterator iter = readoffsets_.find(call_id); if (iter != readoffsets_.end()) - iter->second = offset; + iter->second.offset = offset; else RING_ERR("RingBuffer::storeReadOffset() failed: unknown call '%s'", call_id.c_str()); } - void RingBuffer::createReadOffset(const std::string &call_id) { std::lock_guard<std::mutex> l(lock_); if (!hasThisReadOffset(call_id)) - readoffsets_.insert(std::pair<std::string, int> (call_id, endPos_)); + readoffsets_.emplace(call_id, ReadOffset {endPos_}); } @@ -130,13 +129,11 @@ void RingBuffer::removeReadOffset(const std::string &call_id) { std::lock_guard<std::mutex> l(lock_); - ReadOffset::iterator iter = readoffsets_.find(call_id); - + auto iter = readoffsets_.find(call_id); if (iter != readoffsets_.end()) readoffsets_.erase(iter); } - bool RingBuffer::hasThisReadOffset(const std::string &call_id) const { @@ -153,40 +150,36 @@ bool RingBuffer::hasNoReadOffsets() const // For the writer only: // +void RingBuffer::put(std::shared_ptr<AudioFrame>&& data) +{ + resizer_.enqueue(resampler_.resample(std::move(data), format_)); +} + // This one puts some data inside the ring buffer. -void RingBuffer::put(AudioBuffer& buf) +void RingBuffer::putToBuffer(std::shared_ptr<AudioFrame>&& data) { std::lock_guard<std::mutex> l(lock_); - const size_t sample_num = buf.frames(); - const size_t buffer_size = buffer_.frames(); + const size_t buffer_size = buffer_.size(); if (buffer_size == 0) return; - size_t len = putLength(); - if (buffer_size - len < sample_num) - discard(sample_num); - size_t toCopy = sample_num; - - // Add more channels if the input buffer holds more channels than the ring. - if (buffer_.channels() < buf.channels()) - buffer_.setChannelNum(buf.channels()); + size_t len = buffer_size - putLength(); + if (len == 0) + discard(1); - size_t in_pos = 0; size_t pos = endPos_; - while (toCopy) { - size_t block = toCopy; + buffer_[pos] = std::move(data); + const auto& newBuf = buffer_[pos]; + pos = (pos + 1) % buffer_size; - if (block > buffer_size - pos) // Wrap block around ring ? - block = buffer_size - pos; // Fill in to the end of the buffer + endPos_ = pos; - buffer_.copy(buf, block, in_pos, pos); - in_pos += block; - pos = (pos + block) % buffer_size; - toCopy -= block; + for (auto& offset : readoffsets_) { + if (offset.second.callback) + offset.second.callback(newBuf); } - endPos_ = pos; not_empty_.notify_all(); } @@ -201,64 +194,45 @@ RingBuffer::availableForGet(const std::string &call_id) const return getLength(call_id); } -size_t RingBuffer::get(AudioBuffer& buf, const std::string &call_id) +std::shared_ptr<AudioFrame> +RingBuffer::get(const std::string& call_id) { std::lock_guard<std::mutex> l(lock_); - if (not hasThisReadOffset(call_id)) - return 0; + auto offset = readoffsets_.find(call_id); + if (offset == readoffsets_.end()) + return {}; - const size_t buffer_size = buffer_.frames(); + const size_t buffer_size = buffer_.size(); if (buffer_size == 0) - return 0; - - size_t len = getLength(call_id); - const size_t sample_num = buf.frames(); - size_t toCopy = std::min(sample_num, len); - if (toCopy and toCopy != sample_num) { - RING_DBG("Partial get: %zu/%zu", toCopy, sample_num); - } - - const size_t copied = toCopy; - - size_t dest = 0; - size_t startPos = getReadOffset(call_id); - - while (toCopy > 0) { - size_t block = toCopy; + return {}; - if (block > buffer_size - startPos) - block = buffer_size - startPos; + size_t startPos = offset->second.offset; + size_t len = (endPos_ + buffer_size - startPos) % buffer_size; + if (len == 0) + return {}; - buf.copy(buffer_, block, startPos, dest); - - dest += block; - startPos = (startPos + block) % buffer_size; - toCopy -= block; - } - - storeReadOffset(startPos, call_id); - return copied; + auto ret = buffer_[startPos]; + offset->second.offset = (startPos + 1) % buffer_size; + return ret; } - -size_t RingBuffer::waitForDataAvailable(const std::string &call_id, size_t min_data_length, const time_point& deadline) const +size_t RingBuffer::waitForDataAvailable(const std::string &call_id, const time_point& deadline) const { std::unique_lock<std::mutex> l(lock_); - const size_t buffer_size = buffer_.frames(); - if (buffer_size < min_data_length) return 0; - ReadOffset::const_iterator read_ptr = readoffsets_.find(call_id); - if (read_ptr == readoffsets_.end()) return 0; + if (buffer_.empty()) return 0; + if (readoffsets_.find(call_id) == readoffsets_.end()) return 0; size_t getl = 0; auto check = [=, &getl] { // Re-find read_ptr: it may be destroyed during the wait + const size_t buffer_size = buffer_.size(); const auto read_ptr = readoffsets_.find(call_id); - if (read_ptr == readoffsets_.end()) + if (buffer_size == 0 || read_ptr == readoffsets_.end()) return true; - getl = (endPos_ + buffer_size - read_ptr->second) % buffer_size; - return getl >= min_data_length; + getl = (endPos_ + buffer_size - read_ptr->second.offset) % buffer_size; + return getl != 0; }; if (deadline == time_point::max()) { @@ -272,34 +246,36 @@ size_t RingBuffer::waitForDataAvailable(const std::string &call_id, size_t min_d } size_t -RingBuffer::discard(size_t toDiscard, const std::string &call_id) +RingBuffer::discard(size_t toDiscard, const std::string& call_id) { std::lock_guard<std::mutex> l(lock_); - const size_t buffer_size = buffer_.frames(); + const size_t buffer_size = buffer_.size(); if (buffer_size == 0) return 0; - size_t len = getLength(call_id); - if (toDiscard > len) - toDiscard = len; + auto offset = readoffsets_.find(call_id); + if (offset == readoffsets_.end()) + return 0; + + size_t len = (endPos_ + buffer_size - offset->second.offset) % buffer_size; + toDiscard = std::min(toDiscard, len); - size_t startPos = (getReadOffset(call_id) + toDiscard) % buffer_size; - storeReadOffset(startPos, call_id); + offset->second.offset = (offset->second.offset + toDiscard) % buffer_size; return toDiscard; } size_t RingBuffer::discard(size_t toDiscard) { - const size_t buffer_size = buffer_.frames(); + const size_t buffer_size = buffer_.size(); if (buffer_size == 0) return 0; - for (auto & r : readoffsets_) { - size_t dst = (r.second + buffer_size - endPos_) % buffer_size; + for (auto& r : readoffsets_) { + size_t dst = (r.second.offset + buffer_size - endPos_) % buffer_size; if (dst < toDiscard) - r.second = (r.second + toDiscard - dst) % buffer_size; + r.second.offset = (r.second.offset + toDiscard - dst) % buffer_size; } return toDiscard; } diff --git a/src/media/audio/ringbuffer.h b/src/media/audio/ringbuffer.h index 5db1ec18e5b16983fc5b266bcac11436ebbc9bda..28bf28f0e84c270ae7fb4f1bf6c3081ec36185f3 100644 --- a/src/media/audio/ringbuffer.h +++ b/src/media/audio/ringbuffer.h @@ -25,6 +25,8 @@ #include "audiobuffer.h" #include "noncopyable.h" +#include "audio_frame_resizer.h" +#include "resampler.h" #include <condition_variable> #include <mutex> @@ -43,6 +45,7 @@ class RingBuffer { public: using clock = std::chrono::high_resolution_clock; using time_point = clock::time_point; + using FrameCallback = std::function<void(const std::shared_ptr<AudioFrame>&)>; /** * Constructor @@ -51,6 +54,8 @@ class RingBuffer { RingBuffer(const std::string& id, size_t size, AudioFormat format=AudioFormat::MONO()); + const std::string& getId() const { return id; } + /** * Reset the counters to 0 for this read offset */ @@ -58,12 +63,13 @@ class RingBuffer { void flushAll(); - inline AudioFormat getFormat() const { - return buffer_.getFormat(); + inline AudioFormat getFormat() const { + return format_; } - inline void setFormat(AudioFormat format) { - buffer_.setFormat(format); + inline void setFormat(const AudioFormat& format) { + format_ = format; + resizer_.setFormat(format, format.sample_rate / 50); } /** @@ -71,6 +77,8 @@ class RingBuffer { */ void createReadOffset(const std::string &call_id); + void createReadOffset(const std::string &call_id, FrameCallback cb); + /** * Remove a readoffset for this ringbuffer */ @@ -83,7 +91,7 @@ class RingBuffer { * @param buffer Data to copied * @param toCopy Number of bytes to copy */ - void put(AudioBuffer& buf); + void put(std::shared_ptr<AudioFrame>&& data); /** * To get how much samples are available in the buffer to read in @@ -97,7 +105,7 @@ class RingBuffer { * @param toCopy Number of bytes to copy * @return size_t Number of bytes copied */ - size_t get(AudioBuffer& buf, const std::string &call_id); + std::shared_ptr<AudioFrame> get(const std::string &call_id); /** * Discard data from the buffer @@ -115,7 +123,7 @@ class RingBuffer { size_t getLength(const std::string &call_id) const; inline bool isFull() const { - return putLength() == buffer_.frames(); + return putLength() == buffer_.size(); } inline bool isEmpty() const { @@ -130,19 +138,23 @@ class RingBuffer { * @param deadline The call is guaranteed to end after this time point. If no deadline is provided, the call blocks indefinitely. * @return available data for call_id after the call returned (same as calling getLength(call_id) ). */ - size_t waitForDataAvailable(const std::string& call_id, size_t min_data_length, const time_point& deadline = time_point::max()) const; + size_t waitForDataAvailable(const std::string& call_id, const time_point& deadline = time_point::max()) const; /** * Debug function print mEnd, mStart, mBufferSize */ void debug(); - const std::string id; - private: - using ReadOffset = std::map<std::string, size_t>; + struct ReadOffset { + size_t offset; + FrameCallback callback; + }; + using ReadOffsetMap = std::map<std::string, ReadOffset>; NON_COPYABLE(RingBuffer); + void putToBuffer(std::shared_ptr<AudioFrame>&& data); + bool hasNoReadOffsets() const; /** @@ -170,16 +182,22 @@ class RingBuffer { */ size_t discard(size_t toDiscard); + const std::string id; + /** Offset on the last data */ size_t endPos_; /** Data */ - AudioBuffer buffer_; + AudioFormat format_ {AudioFormat::DEFAULT()}; + std::vector<std::shared_ptr<AudioFrame>> buffer_ {8}; mutable std::mutex lock_; mutable std::condition_variable not_empty_; - ReadOffset readoffsets_; + ReadOffsetMap readoffsets_; + + Resampler resampler_; + AudioFrameResizer resizer_; }; } // namespace ring diff --git a/src/media/audio/ringbufferpool.cpp b/src/media/audio/ringbufferpool.cpp index 2d644d92910b0464874624ddfa644b9276bb914c..8817fb1bb551ba44cc11b7ccc8efc35ca5b4cf47 100644 --- a/src/media/audio/ringbufferpool.cpp +++ b/src/media/audio/ringbufferpool.cpp @@ -111,7 +111,7 @@ RingBufferPool::createRingBuffer(const std::string& id) return rbuf; } - rbuf.reset(new RingBuffer(id, SIZEBUF)); + rbuf.reset(new RingBuffer(id, SIZEBUF, internalAudioFormat_)); RING_DBG("Ringbuffer created with id '%s'", id.c_str()); ringBufferMap_.insert(std::make_pair(id, std::weak_ptr<RingBuffer>(rbuf))); return rbuf; @@ -145,12 +145,12 @@ void RingBufferPool::addReaderToRingBuffer(const std::shared_ptr<RingBuffer>& rbuf, const std::string& call_id) { - if (call_id != DEFAULT_ID and rbuf->id == call_id) + if (call_id != DEFAULT_ID and rbuf->getId() == call_id) RING_WARN("RingBuffer has a readoffset on itself"); rbuf->createReadOffset(call_id); readBindingsMap_[call_id].insert(rbuf); // bindings list created if not existing - RING_DBG("Bind rbuf '%s' to callid '%s'", rbuf->id.c_str(), call_id.c_str()); + RING_DBG("Bind rbuf '%s' to callid '%s'", rbuf->getId().c_str(), call_id.c_str()); } void @@ -251,12 +251,12 @@ RingBufferPool::unBindAll(const std::string& call_id) const auto bindings_copy = *bindings; // temporary copy for (const auto& rbuf : bindings_copy) { removeReaderFromRingBuffer(rbuf, call_id); - removeReaderFromRingBuffer(rb_call, rbuf->id); + removeReaderFromRingBuffer(rb_call, rbuf->getId()); } } -size_t -RingBufferPool::getData(AudioBuffer& buffer, const std::string& call_id) +std::shared_ptr<AudioFrame> +RingBufferPool::getData(const std::string& call_id) { std::lock_guard<std::recursive_mutex> lk(stateLock_); @@ -266,27 +266,21 @@ RingBufferPool::getData(AudioBuffer& buffer, const std::string& call_id) // No mixing if (bindings->size() == 1) - return (*bindings->cbegin())->get(buffer, call_id); - - buffer.reset(); - buffer.setFormat(internalAudioFormat_); + return (*bindings->cbegin())->get(call_id); size_t size = 0; - AudioBuffer mixBuffer(buffer); - + auto mixBuffer = std::make_unique<AudioFrame>(internalAudioFormat_); for (const auto& rbuf : *bindings) { - // XXX: is it normal to only return the last positive size? - size = rbuf->get(mixBuffer, call_id); - if (size > 0) - buffer.mix(mixBuffer); + if (auto b = rbuf->get(call_id)) { + mixBuffer->mix(*b); + } } - return size; + return mixBuffer; } bool RingBufferPool::waitForDataAvailable(const std::string& call_id, - size_t min_frames, const std::chrono::microseconds& max_wait) const { std::unique_lock<std::recursive_mutex> lk(stateLock_); @@ -301,15 +295,15 @@ RingBufferPool::waitForDataAvailable(const std::string& call_id, const auto bindings_copy = *bindings; // temporary copy for (const auto& rbuf : bindings_copy) { lk.unlock(); - if (rbuf->waitForDataAvailable(call_id, min_frames, deadline) < min_frames) + if (rbuf->waitForDataAvailable(call_id, deadline) == 0) return false; lk.lock(); } return true; } -size_t -RingBufferPool::getAvailableData(AudioBuffer& buffer, const std::string& call_id) +std::shared_ptr<AudioFrame> +RingBufferPool::getAvailableData(const std::string& call_id) { std::lock_guard<std::recursive_mutex> lk(stateLock_); @@ -319,32 +313,24 @@ RingBufferPool::getAvailableData(AudioBuffer& buffer, const std::string& call_id // No mixing if (bindings->size() == 1) { - return (*bindings->cbegin())->get(buffer, call_id); + return (*bindings->cbegin())->get(call_id); } - size_t availableSamples = std::numeric_limits<size_t>::max(); + size_t availableFrames = 0; 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_); + availableFrames = std::min(availableFrames, rbuf->availableForGet(call_id)); - AudioBuffer mixBuffer(buffer); + if (availableFrames == 0) + return {}; + auto buf = std::make_unique<AudioFrame>(internalAudioFormat_); for (const auto &rbuf : *bindings) { - if (rbuf->get(mixBuffer, call_id) > 0) - buffer.mix(mixBuffer); + if (auto b = rbuf->get(call_id)) + buf->mix(*b); } - return availableSamples; + return buf; } size_t @@ -365,7 +351,7 @@ RingBufferPool::availableForGet(const std::string& call_id) const for (const auto& rbuf : *bindings) { const size_t nbSamples = rbuf->availableForGet(call_id); - if (nbSamples > 0) + if (nbSamples != 0) availableSamples = std::min(availableSamples, nbSamples); } diff --git a/src/media/audio/ringbufferpool.h b/src/media/audio/ringbufferpool.h index 3a5713579254d39b82aed6be540aaa758e87858a..171f0b711f2c2ea594dcceb13418897ae24c5116 100644 --- a/src/media/audio/ringbufferpool.h +++ b/src/media/audio/ringbufferpool.h @@ -19,8 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef RING_BUFFER_POOL_H_ -#define RING_BUFFER_POOL_H_ +#pragma once #include "audiobuffer.h" #include "noncopyable.h" @@ -36,7 +35,6 @@ namespace ring { class RingBuffer; class RingBufferPool { - public: static const char * const DEFAULT_ID; @@ -86,12 +84,11 @@ class RingBufferPool { void unBindAll(const std::string& call_id); bool waitForDataAvailable(const std::string& call_id, - size_t min_data_length, const std::chrono::microseconds& max_wait) const; - size_t getData(AudioBuffer& buffer, const std::string& call_id); + std::shared_ptr<AudioFrame> getData(const std::string& call_id); - size_t getAvailableData(AudioBuffer& buffer, const std::string& call_id); + std::shared_ptr<AudioFrame> getAvailableData(const std::string& call_id); size_t availableForGet(const std::string& call_id) const; @@ -155,5 +152,3 @@ class RingBufferPool { }; } // namespace ring - -#endif // RING_BUFFER_POOL_H_ diff --git a/src/media/media_decoder.cpp b/src/media/media_decoder.cpp index 670f204371bd544b485d2300c20864a964097468..ccdaf2ddf1053171d27867e4d9a409895bb0b30b 100644 --- a/src/media/media_decoder.cpp +++ b/src/media/media_decoder.cpp @@ -467,36 +467,18 @@ int MediaDecoder::getPixelFormat() const { return decoderCtx_->pix_fmt; } void -MediaDecoder::writeToRingBuffer(const AudioFrame& decodedFrame, +MediaDecoder::writeToRingBuffer(std::unique_ptr<AudioFrame>&& decodedFrame, RingBuffer& rb, const AudioFormat outFormat) { - const auto frame = decodedFrame.pointer(); - const auto inFormat = AudioFormat((unsigned)frame->sample_rate, - (unsigned)frame->channels, - (AVSampleFormat)frame->format); - - AudioFrame output; - if (inFormat != outFormat) { - if (!resampler_) { + AudioFormat format (decoderCtx_->sample_rate, decoderCtx_->channels, decoderCtx_->sample_fmt); + if (format != outFormat) { + if (not resampler_) { RING_DBG("Creating audio resampler"); resampler_.reset(new Resampler); } - auto out = output.pointer(); - out->format = (int)outFormat.sampleFormat; - out->channel_layout = av_get_default_channel_layout((int)outFormat.nb_channels); - out->channels = (int)outFormat.nb_channels; - out->sample_rate = (int)outFormat.sample_rate; - if (resampler_->resample(frame, out) < 0) { - RING_ERR() << "Failed to resample audio"; - return; - } - } else { - output.copyFrom(decodedFrame); + decodedFrame = resampler_->resample(std::move(decodedFrame), outFormat); } - // let buf resize itself - auto buf = AudioBuffer(0, outFormat); - buf.append(output); - rb.put(buf); + rb.put(std::move(decodedFrame)); } int diff --git a/src/media/media_decoder.h b/src/media/media_decoder.h index 329924266bd2822fcec2512af440feb7825259f0..5781777275e6d495bf39c4912c117da73d7ecf05 100644 --- a/src/media/media_decoder.h +++ b/src/media/media_decoder.h @@ -90,7 +90,7 @@ class MediaDecoder { int setupFromAudioData(); Status decode(AudioFrame&); - void writeToRingBuffer(const AudioFrame&, RingBuffer&, const AudioFormat); + void writeToRingBuffer(std::unique_ptr<AudioFrame>&& decodedFrame, RingBuffer&, const AudioFormat); int getWidth() const; int getHeight() const; diff --git a/src/media/media_device.h b/src/media/media_device.h index b8dea845fbc1d96a7cd2bbe6d4aa7f863ee62a19..f4d5b613db69f01296fa2dda4767a81ced45b880 100644 --- a/src/media/media_device.h +++ b/src/media/media_device.h @@ -24,9 +24,12 @@ #include "rational.h" #include <string> +#include <chrono> namespace ring { +constexpr static auto NEWPARAMS_TIMEOUT = std::chrono::milliseconds(1000); + /** * DeviceParams * Parameters used by MediaDecoder and MediaEncoder diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp index 332ceb71fbbfaf7123bfcb7fc22492fd3a86206d..60b4338b9fd5ab764b87a6df56320c8e9a4e0a15 100644 --- a/src/media/video/video_rtp_session.cpp +++ b/src/media/video/video_rtp_session.cpp @@ -46,8 +46,6 @@ namespace ring { namespace video { using std::map; using std::string; -constexpr static auto NEWPARAMS_TIMEOUT = std::chrono::milliseconds(1000); - // how long (in seconds) to wait before rechecking for packet loss static constexpr auto RTCP_PACKET_LOSS_INTERVAL = std::chrono::milliseconds(1000);