1 /*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/audio_device/fine_audio_buffer.h"
12
13 #include <cstdint>
14 #include <cstring>
15
16 #include "modules/audio_device/audio_device_buffer.h"
17 #include "rtc_base/checks.h"
18 #include "rtc_base/logging.h"
19 #include "rtc_base/numerics/safe_conversions.h"
20
21 namespace webrtc {
22
FineAudioBuffer(AudioDeviceBuffer * audio_device_buffer)23 FineAudioBuffer::FineAudioBuffer(AudioDeviceBuffer* audio_device_buffer)
24 : audio_device_buffer_(audio_device_buffer),
25 playout_samples_per_channel_10ms_(rtc::dchecked_cast<size_t>(
26 audio_device_buffer->PlayoutSampleRate() * 10 / 1000)),
27 record_samples_per_channel_10ms_(rtc::dchecked_cast<size_t>(
28 audio_device_buffer->RecordingSampleRate() * 10 / 1000)),
29 playout_channels_(audio_device_buffer->PlayoutChannels()),
30 record_channels_(audio_device_buffer->RecordingChannels()) {
31 RTC_DCHECK(audio_device_buffer_);
32 RTC_DLOG(INFO) << __FUNCTION__;
33 if (IsReadyForPlayout()) {
34 RTC_DLOG(INFO) << "playout_samples_per_channel_10ms: "
35 << playout_samples_per_channel_10ms_;
36 RTC_DLOG(INFO) << "playout_channels: " << playout_channels_;
37 }
38 if (IsReadyForRecord()) {
39 RTC_DLOG(INFO) << "record_samples_per_channel_10ms: "
40 << record_samples_per_channel_10ms_;
41 RTC_DLOG(INFO) << "record_channels: " << record_channels_;
42 }
43 }
44
~FineAudioBuffer()45 FineAudioBuffer::~FineAudioBuffer() {
46 RTC_DLOG(INFO) << __FUNCTION__;
47 }
48
ResetPlayout()49 void FineAudioBuffer::ResetPlayout() {
50 playout_buffer_.Clear();
51 }
52
ResetRecord()53 void FineAudioBuffer::ResetRecord() {
54 record_buffer_.Clear();
55 }
56
IsReadyForPlayout() const57 bool FineAudioBuffer::IsReadyForPlayout() const {
58 return playout_samples_per_channel_10ms_ > 0 && playout_channels_ > 0;
59 }
60
IsReadyForRecord() const61 bool FineAudioBuffer::IsReadyForRecord() const {
62 return record_samples_per_channel_10ms_ > 0 && record_channels_ > 0;
63 }
64
GetPlayoutData(rtc::ArrayView<int16_t> audio_buffer,int playout_delay_ms)65 void FineAudioBuffer::GetPlayoutData(rtc::ArrayView<int16_t> audio_buffer,
66 int playout_delay_ms) {
67 RTC_DCHECK(IsReadyForPlayout());
68 // Ask WebRTC for new data in chunks of 10ms until we have enough to
69 // fulfill the request. It is possible that the buffer already contains
70 // enough samples from the last round.
71 while (playout_buffer_.size() < audio_buffer.size()) {
72 // Get 10ms decoded audio from WebRTC. The ADB knows about number of
73 // channels; hence we can ask for number of samples per channel here.
74 if (audio_device_buffer_->RequestPlayoutData(
75 playout_samples_per_channel_10ms_) ==
76 static_cast<int32_t>(playout_samples_per_channel_10ms_)) {
77 // Append 10ms to the end of the local buffer taking number of channels
78 // into account.
79 const size_t num_elements_10ms =
80 playout_channels_ * playout_samples_per_channel_10ms_;
81 const size_t written_elements = playout_buffer_.AppendData(
82 num_elements_10ms, [&](rtc::ArrayView<int16_t> buf) {
83 const size_t samples_per_channel_10ms =
84 audio_device_buffer_->GetPlayoutData(buf.data());
85 return playout_channels_ * samples_per_channel_10ms;
86 });
87 RTC_DCHECK_EQ(num_elements_10ms, written_elements);
88 } else {
89 // Provide silence if AudioDeviceBuffer::RequestPlayoutData() fails.
90 // Can e.g. happen when an AudioTransport has not been registered.
91 const size_t num_bytes = audio_buffer.size() * sizeof(int16_t);
92 std::memset(audio_buffer.data(), 0, num_bytes);
93 return;
94 }
95 }
96
97 // Provide the requested number of bytes to the consumer.
98 const size_t num_bytes = audio_buffer.size() * sizeof(int16_t);
99 memcpy(audio_buffer.data(), playout_buffer_.data(), num_bytes);
100 // Move remaining samples to start of buffer to prepare for next round.
101 memmove(playout_buffer_.data(), playout_buffer_.data() + audio_buffer.size(),
102 (playout_buffer_.size() - audio_buffer.size()) * sizeof(int16_t));
103 playout_buffer_.SetSize(playout_buffer_.size() - audio_buffer.size());
104 // Cache playout latency for usage in DeliverRecordedData();
105 playout_delay_ms_ = playout_delay_ms;
106 }
107
DeliverRecordedData(rtc::ArrayView<const int16_t> audio_buffer,int record_delay_ms)108 void FineAudioBuffer::DeliverRecordedData(
109 rtc::ArrayView<const int16_t> audio_buffer,
110 int record_delay_ms) {
111 RTC_DCHECK(IsReadyForRecord());
112 // Always append new data and grow the buffer when needed.
113 record_buffer_.AppendData(audio_buffer.data(), audio_buffer.size());
114 // Consume samples from buffer in chunks of 10ms until there is not
115 // enough data left. The number of remaining samples in the cache is given by
116 // the new size of the internal |record_buffer_|.
117 const size_t num_elements_10ms =
118 record_channels_ * record_samples_per_channel_10ms_;
119 while (record_buffer_.size() >= num_elements_10ms) {
120 audio_device_buffer_->SetRecordedBuffer(record_buffer_.data(),
121 record_samples_per_channel_10ms_);
122 audio_device_buffer_->SetVQEData(playout_delay_ms_, record_delay_ms);
123 audio_device_buffer_->DeliverRecordedData();
124 memmove(record_buffer_.data(), record_buffer_.data() + num_elements_10ms,
125 (record_buffer_.size() - num_elements_10ms) * sizeof(int16_t));
126 record_buffer_.SetSize(record_buffer_.size() - num_elements_10ms);
127 }
128 }
129
130 } // namespace webrtc
131