Index: media/audio/win/audio_low_latency_input_win.cc |
diff --git a/media/audio/win/audio_low_latency_input_win.cc b/media/audio/win/audio_low_latency_input_win.cc |
index 22355580aac45b2c656ae6066bd25fd1b72f1a3f..0e6ba96670c5b8a3498fe921f551a5e31bded50f 100644 |
--- a/media/audio/win/audio_low_latency_input_win.cc |
+++ b/media/audio/win/audio_low_latency_input_win.cc |
@@ -15,6 +15,9 @@ |
#include "media/audio/win/avrt_wrapper_win.h" |
#include "media/audio/win/core_audio_util_win.h" |
#include "media/base/audio_bus.h" |
+#include "media/base/channel_layout.h" |
+#include "media/base/limits.h" |
+#include "media/base/multi_channel_resampler.h" |
using base::win::ScopedComPtr; |
using base::win::ScopedCOMInitializer; |
@@ -123,9 +126,10 @@ bool WASAPIAudioInputStream::Open() { |
// Initialize the audio stream between the client and the device using |
// shared mode and a lowest possible glitch-free latency. |
hr = InitializeAudioEngine(); |
+ if (SUCCEEDED(hr) && converter_) |
+ open_result_ = OPEN_RESULT_OK_WITH_RESAMPLING; |
ReportOpenResult(); // Report before we assign a value to |opened_|. |
opened_ = SUCCEEDED(hr); |
- DCHECK(open_result_ == OPEN_RESULT_OK || !opened_); |
return opened_; |
} |
@@ -227,6 +231,9 @@ void WASAPIAudioInputStream::Close() { |
// It is also valid to call Close() after Start() has been called. |
Stop(); |
+ if (converter_) |
+ converter_->RemoveInput(this); |
+ |
// Inform the audio manager that we have been closed. This will cause our |
// destruction. |
manager_->ReleaseInputStream(this); |
@@ -424,8 +431,21 @@ void WASAPIAudioInputStream::Run() { |
// Copy data to audio bus to match the OnData interface. |
uint8_t* audio_data = |
reinterpret_cast<uint8_t*>(capture_buffer.get()); |
- audio_bus_->FromInterleaved(audio_data, audio_bus_->frames(), |
- format_.wBitsPerSample / 8); |
+ |
+ if (converter_) { |
+ convert_bus_->FromInterleaved(audio_data, convert_bus_->frames(), |
+ format_.wBitsPerSample / 8); |
+ data_was_converted_ = false; |
+ converter_->ConvertWithDelay(delay_frames, audio_bus_.get()); |
+ if (!data_was_converted_) { |
+ LOG(ERROR) << "Failed to convert enough samples."; |
DaleCurtis
2017/02/16 02:03:36
Won't this trample whatever you have in audio_bus_
tommi (sloooow) - chröme
2017/02/16 21:59:46
Yes indeed it would. I wasn't able to repro this a
|
+ converter_->ConvertWithDelay(delay_frames, audio_bus_.get()); |
+ } |
+ DCHECK(data_was_converted_); |
+ } else { |
+ audio_bus_->FromInterleaved(audio_data, audio_bus_->frames(), |
+ format_.wBitsPerSample / 8); |
+ } |
// Deliver data packet, delay estimation and volume level to |
// the user. |
@@ -595,6 +615,59 @@ bool WASAPIAudioInputStream::DesiredFormatIsSupported() { |
&format_, &closest_match); |
DLOG_IF(ERROR, hr == S_FALSE) << "Format is not supported " |
<< "but a closest match exists."; |
+ if (hr == S_FALSE && |
+ closest_match->nSamplesPerSec >= limits::kMinSampleRate && |
+ closest_match->nSamplesPerSec <= limits::kMaxSampleRate) { |
+ // We want a 1:1 ratio between the buffers we get and the buffers we |
+ // give to OnData so that each buffer we receive from the OS can be directly |
+ // resampled to a buffer that matches with what the client asked for. |
+ const double buffer_ratio = |
+ format_.nSamplesPerSec / static_cast<double>(audio_bus_->frames()); |
+ const size_t new_frames_per_buffer = |
+ static_cast<size_t>(closest_match->nSamplesPerSec / buffer_ratio); |
+ |
+ const AudioParameters input( |
+ AudioParameters::AUDIO_PCM_LOW_LATENCY, |
+ GuessChannelLayout(closest_match->nChannels), |
DaleCurtis
2017/02/16 02:03:36
Need to check the result of this that it's not CHA
|
+ closest_match->nSamplesPerSec, |
+ // We need to be careful here to not pick the closest wBitsPerSample |
DaleCurtis
2017/02/16 02:03:36
I think this statement is false, or at least shoul
tommi (sloooow) - chröme
2017/02/16 21:59:46
Oh interesting, thanks for pointing that out (and
|
+ // match as we need to use the PCM format (which might not be what |
+ // closeest_match->wFormat is) and the internal resampler doesn't |
+ // support all formats we might get here. So, we stick to the |
+ // wBitsPerSample that was asked for originally (most likely 16). |
+ format_.wBitsPerSample, new_frames_per_buffer); |
+ |
+ const AudioParameters output(AudioParameters::AUDIO_PCM_LOW_LATENCY, |
+ GuessChannelLayout(format_.nChannels), |
+ format_.nSamplesPerSec, format_.wBitsPerSample, |
+ audio_bus_->frames()); |
+ |
+ converter_.reset(new AudioConverter(input, output, false)); |
+ converter_->AddInput(this); |
+ converter_->PrimeWithSilence(); |
+ convert_bus_ = AudioBus::Create(input); |
+ |
+ // Now change the format we're going to ask for to better match with what |
+ // the OS can provide. If we succeed in opening the stream with these |
+ // params, we can take care of the required resampling. |
+ format_.nSamplesPerSec = closest_match->nSamplesPerSec; |
+ format_.nChannels = closest_match->nChannels; |
+ format_.nBlockAlign = (format_.wBitsPerSample / 8) * format_.nChannels; |
+ format_.nAvgBytesPerSec = format_.nSamplesPerSec * format_.nBlockAlign; |
+ |
+ // Update our packet size assumptions based on the new format. |
+ const auto new_bytes_per_buffer = convert_bus_->frames() * |
+ format_.nChannels * |
+ (format_.wBitsPerSample / 8); |
+ packet_size_frames_ = new_bytes_per_buffer / format_.nBlockAlign; |
+ packet_size_bytes_ = new_bytes_per_buffer; |
+ frame_size_ = format_.nBlockAlign; |
+ ms_to_frame_count_ = static_cast<double>(format_.nSamplesPerSec) / 1000.0; |
+ |
+ // Indicate that we're good to go with a close match. |
+ hr = S_OK; |
+ } |
+ |
return (hr == S_OK); |
} |
@@ -738,4 +811,11 @@ void WASAPIAudioInputStream::ReportOpenResult() const { |
OPEN_RESULT_MAX + 1); |
} |
+double WASAPIAudioInputStream::ProvideInput(AudioBus* audio_bus, |
+ uint32_t frames_delayed) { |
+ convert_bus_->CopyTo(audio_bus); |
+ data_was_converted_ = true; |
+ return 1.0; |
+} |
+ |
} // namespace media |