|  | /* | 
|  | *  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_(dchecked_cast<size_t>( | 
|  | audio_device_buffer->PlayoutSampleRate() * 10 / 1000)), | 
|  | record_samples_per_channel_10ms_(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(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, [&](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( | 
|  | 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 |