Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Unified Diff: extensions/renderer/api/display_source/wifi_display/wifi_display_audio_encoder_lpcm.cc

Issue 1903823002: [chrome.displaySource] Implement LPCM audio encoder. (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Comments Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « extensions/renderer/api/display_source/wifi_display/wifi_display_audio_encoder.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: extensions/renderer/api/display_source/wifi_display/wifi_display_audio_encoder_lpcm.cc
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_audio_encoder_lpcm.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_audio_encoder_lpcm.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4e91de25f99c835f47484e87b2552d08263216a2
--- /dev/null
+++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_audio_encoder_lpcm.cc
@@ -0,0 +1,237 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/renderer/api/display_source/wifi_display/wifi_display_audio_encoder.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/sys_byteorder.h"
+#include "extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_descriptor.h"
+#include "extensions/renderer/api/display_source/wifi_display/wifi_display_elementary_stream_info.h"
+#include "extensions/renderer/api/display_source/wifi_display/wifi_display_media_packetizer.h"
+#include "media/base/audio_bus.h"
+#include "media/base/audio_converter.h"
+#include "media/base/audio_parameters.h"
+
+namespace extensions {
+
+namespace {
+
+using LPCMAudioStreamDescriptor =
+ WiFiDisplayElementaryStreamDescriptor::LPCMAudioStream;
+
+// This audio encoder implements Linear Pulse-Code Modulation (LPCM) audio
+// encoding.
+class WiFiDisplayAudioEncoderLPCM final
+ : public WiFiDisplayAudioEncoder,
+ private media::AudioConverter::InputCallback {
+ public:
+ enum {
+ kOutputBitsPerSample = 16,
+ kOutputBytesPerSample = kOutputBitsPerSample / 8,
+ kOutputChannels = 2
+ };
+
+ explicit WiFiDisplayAudioEncoderLPCM(const wds::AudioCodec& audio_codec);
+
+ protected:
+ ~WiFiDisplayAudioEncoderLPCM() override = default;
+
+ // WiFiDisplayMediaEncoder
+ WiFiDisplayElementaryStreamInfo CreateElementaryStreamInfo() const override;
+
+ // content::MediaStreamAudioSink
+ void OnData(const media::AudioBus& input_bus,
+ base::TimeTicks estimated_capture_time) override;
+ void OnSetFormat(const media::AudioParameters& params) override;
+
+ // media::AudioConverter::InputCallback
+ double ProvideInput(media::AudioBus* audio_bus,
+ base::TimeDelta buffer_delay) override;
+
+ LPCMAudioStreamDescriptor::SamplingFrequency GetOutputSamplingFrequency()
+ const;
+
+ private:
+ const int output_sample_rate_;
+
+ // These members are accessed on the real-time audio time only.
+ std::unique_ptr<media::AudioConverter> converter_;
+ const media::AudioBus* current_input_bus_;
+ int64_t input_frames_in_;
+ media::AudioParameters input_params_;
+ std::unique_ptr<media::AudioBus> fifo_bus_;
+ int fifo_end_frame_;
+ int64_t fifo_frames_out_;
+};
+
+WiFiDisplayAudioEncoderLPCM::WiFiDisplayAudioEncoderLPCM(
+ const wds::AudioCodec& audio_codec)
+ : WiFiDisplayAudioEncoder(audio_codec),
+ output_sample_rate_(
+ GetOutputSamplingFrequency() ==
+ LPCMAudioStreamDescriptor::SAMPLING_FREQUENCY_48K
+ ? 48000
+ : 44100),
+ current_input_bus_(nullptr),
+ input_frames_in_(0),
+ fifo_end_frame_(0),
+ fifo_frames_out_(0) {}
+
+WiFiDisplayElementaryStreamInfo
+WiFiDisplayAudioEncoderLPCM::CreateElementaryStreamInfo() const {
+ DCHECK(client_thread_checker_.CalledOnValidThread());
+ std::vector<WiFiDisplayElementaryStreamDescriptor> descriptors;
+ descriptors.push_back(LPCMAudioStreamDescriptor::Create(
+ GetOutputSamplingFrequency(),
+ LPCMAudioStreamDescriptor::BITS_PER_SAMPLE_16,
+ false, // emphasis_flag
+ LPCMAudioStreamDescriptor::NUMBER_OF_CHANNELS_STEREO));
+ return WiFiDisplayElementaryStreamInfo(
+ WiFiDisplayElementaryStreamInfo::AUDIO_LPCM, std::move(descriptors));
+}
+
+// Called on real-time audio thread.
+void WiFiDisplayAudioEncoderLPCM::OnData(
+ const media::AudioBus& input_bus,
+ base::TimeTicks estimated_capture_time) {
+ DCHECK(input_params_.IsValid());
+ DCHECK_EQ(input_bus.channels(), input_params_.channels());
+ DCHECK_EQ(input_bus.frames(), input_params_.frames_per_buffer());
+ DCHECK(!estimated_capture_time.is_null());
+
+ const media::AudioBus* source_bus = &input_bus;
+
+ std::unique_ptr<media::AudioBus> converted_input_bus;
+ if (converter_) {
+ // Convert the entire input signal.
+ // Note that while the number of sample frames provided as input is always
+ // the same, the chunk size (and the size of the |converted_input_bus|
+ // here) can be variable.
+ converted_input_bus =
+ media::AudioBus::Create(kOutputChannels, converter_->ChunkSize());
+ current_input_bus_ = &input_bus;
+ converter_->Convert(converted_input_bus.get());
+ DCHECK(!current_input_bus_);
+ source_bus = converted_input_bus.get();
+ }
+
+ // Loop in order to handle frame number differences between |source_bus| and
+ // |fifo_bus_|.
+ int source_start_frame = 0;
+ do {
+ // Copy as many source frames (either raw or converted input frames) as
+ // possible to |fifo_bus_|.
+ int frame_count = std::min(source_bus->frames() - source_start_frame,
+ fifo_bus_->frames() - fifo_end_frame_);
+ DCHECK_GT(frame_count, 0);
+ source_bus->CopyPartialFramesTo(source_start_frame, frame_count,
+ fifo_end_frame_, fifo_bus_.get());
+ fifo_end_frame_ += frame_count;
+ source_start_frame += frame_count;
+
+ if (fifo_end_frame_ == fifo_bus_->frames()) {
+ // There are enough frames in |fifo_bus_| for one encoded unit.
+
+ // Determine the duration of the audio signal enqueued within
+ // |converter_| and |fifo_bus_|.
+ const base::TimeDelta signal_duration_already_buffered =
+ (input_frames_in_ * base::TimeDelta::FromSeconds(1) /
+ input_params_.sample_rate()) -
+ (fifo_frames_out_ * base::TimeDelta::FromSeconds(1) /
+ output_sample_rate_);
+ DVLOG(2) << "Audio reference time adjustment: -("
+ << signal_duration_already_buffered.InMicroseconds() << " us)";
+ const base::TimeTicks capture_time_of_first_converted_sample =
+ estimated_capture_time - signal_duration_already_buffered;
+
+ // Encode frames in |fifo_bus_|.
+ std::string data;
+ int sample_count = fifo_bus_->channels() * fifo_bus_->frames();
+ data.resize(sample_count * sizeof(uint16_t));
+ uint16_t* encoded_samples =
+ reinterpret_cast<uint16_t*>(string_as_array(&data));
+ fifo_bus_->ToInterleaved(fifo_bus_->frames(), kOutputBytesPerSample,
+ encoded_samples);
+ for (int i = 0; i < sample_count; ++i)
+ encoded_samples[i] = base::HostToNet16(encoded_samples[i]);
+ fifo_end_frame_ = 0;
+ fifo_frames_out_ += fifo_bus_->frames();
+
+ // Pass the encoded unit to the client.
+ encoded_callback_.Run(
+ std::unique_ptr<WiFiDisplayEncodedUnit>(new WiFiDisplayEncodedUnit(
+ std::move(data), capture_time_of_first_converted_sample, true)));
+ }
+ } while (source_start_frame < source_bus->frames());
+}
+
+// Called on real-time audio thread.
+void WiFiDisplayAudioEncoderLPCM::OnSetFormat(
+ const media::AudioParameters& params) {
+ if (input_params_.Equals(params))
+ return;
+ input_params_ = params;
+
+ if (output_sample_rate_ != input_params_.sample_rate()) {
+ const media::AudioParameters output_params(
+ media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ media::CHANNEL_LAYOUT_STEREO, output_sample_rate_, kOutputBitsPerSample,
+ WiFiDisplayMediaPacketizer::LPCM::kChannelSamplesPerUnit);
+ DVLOG(2) << "Setting up audio resampling: "
+ << input_params_.sample_rate() << " Hz --> "
+ << output_sample_rate_ << " Hz";
+ converter_.reset(
+ new media::AudioConverter(input_params_, output_params, false));
+ converter_->AddInput(this);
+ } else {
+ // Do not use an AudioConverter if that is not needed in order to avoid
+ // additional copyings caused by additional intermediate audio busses
+ // needed for capturing enough samples for each encoded unit.
+ converter_.reset();
+ }
+
+ fifo_bus_ = media::AudioBus::Create(
+ kOutputChannels,
+ WiFiDisplayMediaPacketizer::LPCM::kChannelSamplesPerUnit);
+ fifo_end_frame_ = 0;
+ fifo_frames_out_ = 0;
+ input_frames_in_ = 0;
+}
+
+// Called on real-time audio thread by |converter_| invoked by |OnData|.
+double WiFiDisplayAudioEncoderLPCM::ProvideInput(media::AudioBus* audio_bus,
+ base::TimeDelta buffer_delay) {
+ DCHECK(current_input_bus_);
+ current_input_bus_->CopyTo(audio_bus);
+ current_input_bus_ = nullptr;
+ return 1.0;
+}
+
+LPCMAudioStreamDescriptor::SamplingFrequency
+WiFiDisplayAudioEncoderLPCM::GetOutputSamplingFrequency() const {
+ switch (GetAudioCodecMode()) {
+ case wds::LPCM_44_1K_16B_2CH:
+ return LPCMAudioStreamDescriptor::SAMPLING_FREQUENCY_44_1K;
+ case wds::LPCM_48K_16B_2CH:
+ return LPCMAudioStreamDescriptor::SAMPLING_FREQUENCY_48K;
+ default:
+ NOTREACHED();
+ return LPCMAudioStreamDescriptor::SAMPLING_FREQUENCY_44_1K;
+ }
+}
+
+} // namespace
+
+void WiFiDisplayAudioEncoder::CreateLPCM(
+ const wds::AudioCodec& audio_codec,
+ const AudioEncoderCallback& encoder_callback) {
+ encoder_callback.Run(
+ make_scoped_refptr(new WiFiDisplayAudioEncoderLPCM(audio_codec)));
+}
+
+} // namespace extensions
« no previous file with comments | « extensions/renderer/api/display_source/wifi_display/wifi_display_audio_encoder.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698