• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(LS_INFO) << __FUNCTION__;
33   if (IsReadyForPlayout()) {
34     RTC_DLOG(LS_INFO) << "playout_samples_per_channel_10ms: "
35                       << playout_samples_per_channel_10ms_;
36     RTC_DLOG(LS_INFO) << "playout_channels: " << playout_channels_;
37   }
38   if (IsReadyForRecord()) {
39     RTC_DLOG(LS_INFO) << "record_samples_per_channel_10ms: "
40                       << record_samples_per_channel_10ms_;
41     RTC_DLOG(LS_INFO) << "record_channels: " << record_channels_;
42   }
43 }
44 
~FineAudioBuffer()45 FineAudioBuffer::~FineAudioBuffer() {
46   RTC_DLOG(LS_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