| Index: remoting/protocol/audio_pump.cc
|
| diff --git a/remoting/protocol/audio_pump.cc b/remoting/protocol/audio_pump.cc
|
| index 66eff6ebff4d58946b7746163d2b9a1c32c2ef20..19a06bc44f7e0e13ec3e09552583cc32939758f6 100644
|
| --- a/remoting/protocol/audio_pump.cc
|
| +++ b/remoting/protocol/audio_pump.cc
|
| @@ -4,19 +4,89 @@
|
|
|
| #include "remoting/protocol/audio_pump.h"
|
|
|
| +#include <memory>
|
| #include <utility>
|
|
|
| #include "base/bind.h"
|
| #include "base/location.h"
|
| #include "base/logging.h"
|
| #include "base/macros.h"
|
| +#include "base/memory/ptr_util.h"
|
| #include "base/single_thread_task_runner.h"
|
| #include "base/threading/thread_task_runner_handle.h"
|
| +#include "media/base/audio_bus.h"
|
| +#include "media/base/audio_sample_types.h"
|
| +#include "media/base/channel_layout.h"
|
| +#include "media/base/channel_mixer.h"
|
| #include "remoting/codec/audio_encoder.h"
|
| #include "remoting/proto/audio.pb.h"
|
| #include "remoting/protocol/audio_source.h"
|
| #include "remoting/protocol/audio_stub.h"
|
|
|
| +namespace {
|
| +
|
| +int CalculateFrameCount(const remoting::AudioPacket& packet) {
|
| + return packet.data(0).size() / packet.channels() / packet.bytes_per_sample();
|
| +}
|
| +
|
| +std::unique_ptr<media::AudioBus> AudioPacketToAudioBus(
|
| + const remoting::AudioPacket& packet) {
|
| + const int frame_count = CalculateFrameCount(packet);
|
| + if (frame_count < 1) {
|
| + return nullptr;
|
| + }
|
| +
|
| + std::unique_ptr<media::AudioBus> result =
|
| + media::AudioBus::Create(packet.channels(), frame_count);
|
| + result->FromInterleaved<media::SignedInt16SampleTypeTraits>(
|
| + reinterpret_cast<const int16_t*>(packet.data(0).data()), frame_count);
|
| + return result;
|
| +}
|
| +
|
| +std::unique_ptr<remoting::AudioPacket> AudioBusToAudioPacket(
|
| + const media::AudioBus& packet) {
|
| + std::unique_ptr<remoting::AudioPacket> result =
|
| + base::MakeUnique<remoting::AudioPacket>();
|
| + result->add_data()->resize(
|
| + packet.channels() * packet.frames() * sizeof(int16_t));
|
| + packet.ToInterleaved<media::SignedInt16SampleTypeTraits>(
|
| + packet.frames(),
|
| + reinterpret_cast<int16_t*>(&(result->mutable_data(0)->at(0))));
|
| + result->set_encoding(remoting::AudioPacket::ENCODING_RAW);
|
| + result->set_channels(
|
| + static_cast<remoting::AudioPacket::Channels>(packet.channels()));
|
| + result->set_bytes_per_sample(remoting::AudioPacket::BYTES_PER_SAMPLE_2);
|
| + return result;
|
| +}
|
| +
|
| +media::ChannelLayout RetrieveLayout(const remoting::AudioPacket& packet) {
|
| + // This switch should match AudioPacket::Channels enum in audio.proto.
|
| + switch (packet.channels()) {
|
| + case remoting::AudioPacket::CHANNELS_INVALID:
|
| + return media::CHANNEL_LAYOUT_UNSUPPORTED;
|
| + case remoting::AudioPacket::CHANNELS_MONO:
|
| + return media::CHANNEL_LAYOUT_MONO;
|
| + case remoting::AudioPacket::CHANNELS_STEREO:
|
| + return media::CHANNEL_LAYOUT_STEREO;
|
| + case remoting::AudioPacket::CHANNELS_SURROUND:
|
| + return media::CHANNEL_LAYOUT_SURROUND;
|
| + case remoting::AudioPacket::CHANNELS_4_0:
|
| + return media::CHANNEL_LAYOUT_4_0;
|
| + case remoting::AudioPacket::CHANNELS_4_1:
|
| + return media::CHANNEL_LAYOUT_4_1;
|
| + case remoting::AudioPacket::CHANNELS_5_1:
|
| + return media::CHANNEL_LAYOUT_5_1;
|
| + case remoting::AudioPacket::CHANNELS_6_1:
|
| + return media::CHANNEL_LAYOUT_6_1;
|
| + case remoting::AudioPacket::CHANNELS_7_1:
|
| + return media::CHANNEL_LAYOUT_7_1;
|
| + }
|
| + NOTREACHED() << "Invalid AudioPacket::Channels";
|
| + return media::CHANNEL_LAYOUT_UNSUPPORTED;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| namespace remoting {
|
| namespace protocol {
|
|
|
| @@ -36,6 +106,8 @@ class AudioPump::Core {
|
| void OnPacketSent(int size);
|
|
|
| private:
|
| + std::unique_ptr<AudioPacket> Downmix(std::unique_ptr<AudioPacket> packet);
|
| +
|
| void EncodeAudioPacket(std::unique_ptr<AudioPacket> packet);
|
|
|
| base::ThreadChecker thread_checker_;
|
| @@ -53,6 +125,9 @@ class AudioPump::Core {
|
| // yet.
|
| int bytes_pending_;
|
|
|
| + std::unique_ptr<media::ChannelMixer> mixer_;
|
| + media::ChannelLayout mixer_input_layout_ = media::CHANNEL_LAYOUT_NONE;
|
| +
|
| DISALLOW_COPY_AND_ASSIGN(Core);
|
| };
|
|
|
| @@ -98,8 +173,13 @@ void AudioPump::Core::EncodeAudioPacket(std::unique_ptr<AudioPacket> packet) {
|
|
|
| int max_buffered_bytes =
|
| audio_encoder_->GetBitrate() * kMaxBufferedIntervalMs / 1000 / 8;
|
| - if (!enabled_ || bytes_pending_ > max_buffered_bytes)
|
| + if (!enabled_ || bytes_pending_ > max_buffered_bytes) {
|
| return;
|
| + }
|
| +
|
| + if (packet->channels() > AudioPacket::CHANNELS_STEREO) {
|
| + packet = Downmix(std::move(packet));
|
| + }
|
|
|
| std::unique_ptr<AudioPacket> encoded_packet =
|
| audio_encoder_->Encode(std::move(packet));
|
| @@ -116,6 +196,41 @@ void AudioPump::Core::EncodeAudioPacket(std::unique_ptr<AudioPacket> packet) {
|
| base::Passed(&encoded_packet), packet_size));
|
| }
|
|
|
| +std::unique_ptr<AudioPacket> AudioPump::Core::Downmix(
|
| + std::unique_ptr<AudioPacket> packet) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(packet);
|
| + DCHECK_EQ(packet->data_size(), 1);
|
| + DCHECK_EQ(packet->bytes_per_sample(), AudioPacket::BYTES_PER_SAMPLE_2);
|
| +
|
| + const media::ChannelLayout input_layout = RetrieveLayout(*packet);
|
| + if (input_layout == media::CHANNEL_LAYOUT_UNSUPPORTED) {
|
| + return nullptr;
|
| + }
|
| + if (input_layout == media::CHANNEL_LAYOUT_MONO ||
|
| + input_layout == media::CHANNEL_LAYOUT_STEREO) {
|
| + return packet;
|
| + }
|
| +
|
| + if (!mixer_ || mixer_input_layout_ != input_layout) {
|
| + mixer_input_layout_ = input_layout;
|
| + mixer_ = base::MakeUnique<media::ChannelMixer>(
|
| + input_layout, media::CHANNEL_LAYOUT_STEREO);
|
| + }
|
| +
|
| + std::unique_ptr<media::AudioBus> input = AudioPacketToAudioBus(*packet);
|
| + if (!input) {
|
| + return nullptr;
|
| + }
|
| + std::unique_ptr<media::AudioBus> output =
|
| + media::AudioBus::Create(AudioPacket::CHANNELS_STEREO, input->frames());
|
| + mixer_->Transform(input.get(), output.get());
|
| +
|
| + std::unique_ptr<AudioPacket> result = AudioBusToAudioPacket(*output);
|
| + result->set_sampling_rate(packet->sampling_rate());
|
| + return result;
|
| +}
|
| +
|
| AudioPump::AudioPump(
|
| scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner,
|
| std::unique_ptr<AudioSource> audio_source,
|
|
|