blob: c872988ae03cc45ceaedc515cafb84502c20af87 [file] [log] [blame]
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/audio_device/fine_audio_buffer.h"
#include <cstdint>
#include <cstring>
#include "api/array_view.h"
#include "modules/audio_device/audio_device_buffer.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
namespace webrtc {
FineAudioBuffer::FineAudioBuffer(AudioDeviceBuffer* audio_device_buffer)
: audio_device_buffer_(audio_device_buffer),
playout_samples_per_channel_10ms_(rtc::dchecked_cast<size_t>(
audio_device_buffer->PlayoutSampleRate() * 10 / 1000)),
record_samples_per_channel_10ms_(rtc::dchecked_cast<size_t>(
audio_device_buffer->RecordingSampleRate() * 10 / 1000)),
playout_channels_(audio_device_buffer->PlayoutChannels()),
record_channels_(audio_device_buffer->RecordingChannels()) {
RTC_DCHECK(audio_device_buffer_);
RTC_DLOG(LS_INFO) << __FUNCTION__;
if (IsReadyForPlayout()) {
RTC_DLOG(LS_INFO) << "playout_samples_per_channel_10ms: "
<< playout_samples_per_channel_10ms_;
RTC_DLOG(LS_INFO) << "playout_channels: " << playout_channels_;
}
if (IsReadyForRecord()) {
RTC_DLOG(LS_INFO) << "record_samples_per_channel_10ms: "
<< record_samples_per_channel_10ms_;
RTC_DLOG(LS_INFO) << "record_channels: " << record_channels_;
}
}
FineAudioBuffer::~FineAudioBuffer() {
RTC_DLOG(LS_INFO) << __FUNCTION__;
}
void FineAudioBuffer::ResetPlayout() {
playout_buffer_.Clear();
}
void FineAudioBuffer::ResetRecord() {
record_buffer_.Clear();
}
bool FineAudioBuffer::IsReadyForPlayout() const {
return playout_samples_per_channel_10ms_ > 0 && playout_channels_ > 0;
}
bool FineAudioBuffer::IsReadyForRecord() const {
return record_samples_per_channel_10ms_ > 0 && record_channels_ > 0;
}
void FineAudioBuffer::GetPlayoutData(rtc::ArrayView<int16_t> audio_buffer,
int playout_delay_ms) {
RTC_DCHECK(IsReadyForPlayout());
// Ask WebRTC for new data in chunks of 10ms until we have enough to
// fulfill the request. It is possible that the buffer already contains
// enough samples from the last round.
while (playout_buffer_.size() < audio_buffer.size()) {
// Get 10ms decoded audio from WebRTC. The ADB knows about number of
// channels; hence we can ask for number of samples per channel here.
if (audio_device_buffer_->RequestPlayoutData(
playout_samples_per_channel_10ms_) ==
static_cast<int32_t>(playout_samples_per_channel_10ms_)) {
// Append 10ms to the end of the local buffer taking number of channels
// into account.
const size_t num_elements_10ms =
playout_channels_ * playout_samples_per_channel_10ms_;
const size_t written_elements = playout_buffer_.AppendData(
num_elements_10ms, [&](rtc::ArrayView<int16_t> buf) {
const size_t samples_per_channel_10ms =
audio_device_buffer_->GetPlayoutData(buf.data());
return playout_channels_ * samples_per_channel_10ms;
});
RTC_DCHECK_EQ(num_elements_10ms, written_elements);
} else {
// Provide silence if AudioDeviceBuffer::RequestPlayoutData() fails.
// Can e.g. happen when an AudioTransport has not been registered.
const size_t num_bytes = audio_buffer.size() * sizeof(int16_t);
std::memset(audio_buffer.data(), 0, num_bytes);
return;
}
}
// Provide the requested number of bytes to the consumer.
const size_t num_bytes = audio_buffer.size() * sizeof(int16_t);
memcpy(audio_buffer.data(), playout_buffer_.data(), num_bytes);
// Move remaining samples to start of buffer to prepare for next round.
memmove(playout_buffer_.data(), playout_buffer_.data() + audio_buffer.size(),
(playout_buffer_.size() - audio_buffer.size()) * sizeof(int16_t));
playout_buffer_.SetSize(playout_buffer_.size() - audio_buffer.size());
// Cache playout latency for usage in DeliverRecordedData();
playout_delay_ms_ = playout_delay_ms;
}
void FineAudioBuffer::DeliverRecordedData(
rtc::ArrayView<const int16_t> audio_buffer,
int record_delay_ms,
std::optional<int64_t> capture_time_ns) {
RTC_DCHECK(IsReadyForRecord());
// Always append new data and grow the buffer when needed.
record_buffer_.AppendData(audio_buffer.data(), audio_buffer.size());
// Consume samples from buffer in chunks of 10ms until there is not
// enough data left. The number of remaining samples in the cache is given by
// the new size of the internal `record_buffer_`.
const size_t num_elements_10ms =
record_channels_ * record_samples_per_channel_10ms_;
while (record_buffer_.size() >= num_elements_10ms) {
audio_device_buffer_->SetRecordedBuffer(record_buffer_.data(),
record_samples_per_channel_10ms_,
capture_time_ns);
audio_device_buffer_->SetVQEData(playout_delay_ms_, record_delay_ms);
audio_device_buffer_->DeliverRecordedData();
memmove(record_buffer_.data(), record_buffer_.data() + num_elements_10ms,
(record_buffer_.size() - num_elements_10ms) * sizeof(int16_t));
record_buffer_.SetSize(record_buffer_.size() - num_elements_10ms);
}
}
} // namespace webrtc