Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/protocol/audio_pump.h" | 5 #include "remoting/protocol/audio_pump.h" |
| 6 | 6 |
| 7 #include <memory> | |
| 7 #include <utility> | 8 #include <utility> |
| 8 | 9 |
| 9 #include "base/bind.h" | 10 #include "base/bind.h" |
| 10 #include "base/location.h" | 11 #include "base/location.h" |
| 11 #include "base/logging.h" | 12 #include "base/logging.h" |
| 12 #include "base/macros.h" | 13 #include "base/macros.h" |
| 14 #include "base/memory/ptr_util.h" | |
| 13 #include "base/single_thread_task_runner.h" | 15 #include "base/single_thread_task_runner.h" |
| 14 #include "base/threading/thread_task_runner_handle.h" | 16 #include "base/threading/thread_task_runner_handle.h" |
| 17 #include "media/base/audio_bus.h" | |
| 18 #include "media/base/audio_sample_types.h" | |
| 19 #include "media/base/channel_layout.h" | |
| 20 #include "media/base/channel_mixer.h" | |
| 15 #include "remoting/codec/audio_encoder.h" | 21 #include "remoting/codec/audio_encoder.h" |
| 16 #include "remoting/proto/audio.pb.h" | 22 #include "remoting/proto/audio.pb.h" |
| 17 #include "remoting/protocol/audio_source.h" | 23 #include "remoting/protocol/audio_source.h" |
| 18 #include "remoting/protocol/audio_stub.h" | 24 #include "remoting/protocol/audio_stub.h" |
| 19 | 25 |
| 26 namespace { | |
| 27 | |
| 28 int CalculateFrameCount(const remoting::AudioPacket& packet) { | |
| 29 return packet.data(0).size() / packet.channels() / packet.bytes_per_sample(); | |
|
joedow
2017/05/26 16:01:50
Could an empty packet be passed in here (with the
Hzj_jie
2017/05/26 20:08:03
AudioPump uses an AudioSource interface. So assumi
| |
| 30 } | |
| 31 | |
| 32 std::unique_ptr<media::AudioBus> ToAudioBus( | |
|
joedow
2017/05/26 16:01:50
nit: Rename to 'PacketToAudioBus' ?
Hzj_jie
2017/05/26 20:08:03
Done.
| |
| 33 const remoting::AudioPacket& packet) { | |
| 34 using namespace media; | |
|
joedow
2017/05/26 16:01:50
The inline using directives are a bit repetitive.
Hzj_jie
2017/05/26 20:08:03
Done.
| |
| 35 const int frame_count = CalculateFrameCount(packet); | |
| 36 if (frame_count <= 0) { | |
|
joedow
2017/05/26 16:01:50
nit: 'frame_count < 1' is simpler
Hzj_jie
2017/05/26 20:08:03
Done.
| |
| 37 return nullptr; | |
| 38 } | |
| 39 if (static_cast<int>(packet.data(0).size()) >= | |
| 40 AudioBus::CalculateMemorySize(packet.channels(), frame_count)) { | |
| 41 // AudioBus::BuildChannelData() should receive const float* instead of | |
| 42 // float*, meanwhile WrapMemory() function. | |
|
joedow
2017/05/26 16:01:50
Can you fix this sentence fragment. The first bit
Hzj_jie
2017/05/26 20:08:03
Done.
| |
| 43 return media::AudioBus::WrapMemory( | |
| 44 packet.channels(), | |
| 45 frame_count, | |
| 46 reinterpret_cast<int16_t*>(const_cast<char*>(packet.data(0).data()))); | |
| 47 } | |
| 48 | |
| 49 std::unique_ptr<AudioBus> result = | |
| 50 AudioBus::Create(packet.channels(), frame_count); | |
| 51 result->FromInterleaved<SignedInt16SampleTypeTraits>( | |
| 52 reinterpret_cast<const int16_t*>(packet.data(0).data()), frame_count); | |
| 53 return result; | |
| 54 } | |
| 55 | |
| 56 std::unique_ptr<remoting::AudioPacket> FromAudioBus( | |
| 57 const media::AudioBus& packet) { | |
| 58 using namespace media; | |
| 59 using remoting::AudioPacket; | |
| 60 std::unique_ptr<AudioPacket> result = base::MakeUnique<AudioPacket>(); | |
| 61 result->add_data()->resize( | |
| 62 AudioBus::CalculateMemorySize(packet.channels(), packet.frames()) / | |
| 63 sizeof(float) * sizeof(int16_t)); | |
| 64 packet.ToInterleaved<SignedInt16SampleTypeTraits>( | |
| 65 packet.frames(), | |
| 66 reinterpret_cast<int16_t*>(&(result->mutable_data(0)->at(0)))); | |
| 67 return result; | |
| 68 } | |
| 69 | |
| 70 media::ChannelLayout RetrieveLayout(const remoting::AudioPacket& packet) { | |
| 71 // This switch should match AudioPacket::Channels enum in audio.proto. | |
| 72 using namespace media; | |
| 73 using remoting::AudioPacket; | |
| 74 switch (packet.channels()) { | |
| 75 case AudioPacket::CHANNELS_INVALID: | |
| 76 return CHANNEL_LAYOUT_UNSUPPORTED; | |
| 77 case AudioPacket::CHANNELS_MONO: | |
| 78 return CHANNEL_LAYOUT_MONO; | |
| 79 case AudioPacket::CHANNELS_STEREO: | |
| 80 return CHANNEL_LAYOUT_STEREO; | |
| 81 case AudioPacket::CHANNELS_5_1: | |
| 82 return CHANNEL_LAYOUT_5_1; | |
| 83 case AudioPacket::CHANNELS_6_1: | |
| 84 return CHANNEL_LAYOUT_6_1; | |
| 85 case AudioPacket::CHANNELS_7_1: | |
| 86 return CHANNEL_LAYOUT_7_1; | |
| 87 } | |
| 88 NOTREACHED() << "Invalid AudioPacket::Channels"; | |
| 89 return CHANNEL_LAYOUT_UNSUPPORTED; | |
| 90 } | |
| 91 | |
| 92 } // namespace | |
| 93 | |
| 20 namespace remoting { | 94 namespace remoting { |
| 21 namespace protocol { | 95 namespace protocol { |
| 22 | 96 |
| 23 // Limit the data stored in the pending send buffers to 250ms. | 97 // Limit the data stored in the pending send buffers to 250ms. |
| 24 const int kMaxBufferedIntervalMs = 250; | 98 const int kMaxBufferedIntervalMs = 250; |
| 25 | 99 |
| 26 class AudioPump::Core { | 100 class AudioPump::Core { |
| 27 public: | 101 public: |
| 28 Core(base::WeakPtr<AudioPump> pump, | 102 Core(base::WeakPtr<AudioPump> pump, |
| 29 std::unique_ptr<AudioSource> audio_source, | 103 std::unique_ptr<AudioSource> audio_source, |
| 30 std::unique_ptr<AudioEncoder> audio_encoder); | 104 std::unique_ptr<AudioEncoder> audio_encoder); |
| 31 ~Core(); | 105 ~Core(); |
| 32 | 106 |
| 33 void Start(); | 107 void Start(); |
| 34 void Pause(bool pause); | 108 void Pause(bool pause); |
| 35 | 109 |
| 36 void OnPacketSent(int size); | 110 void OnPacketSent(int size); |
| 37 | 111 |
| 38 private: | 112 private: |
| 113 std::unique_ptr<remoting::AudioPacket> Downmix( | |
| 114 std::unique_ptr<remoting::AudioPacket> packet); | |
|
joedow
2017/05/26 16:01:50
You don't need the remote prefix here since it is
Hzj_jie
2017/05/26 20:08:03
Done.
| |
| 115 | |
| 39 void EncodeAudioPacket(std::unique_ptr<AudioPacket> packet); | 116 void EncodeAudioPacket(std::unique_ptr<AudioPacket> packet); |
| 40 | 117 |
| 41 base::ThreadChecker thread_checker_; | 118 base::ThreadChecker thread_checker_; |
| 42 | 119 |
| 43 base::WeakPtr<AudioPump> pump_; | 120 base::WeakPtr<AudioPump> pump_; |
| 44 | 121 |
| 45 scoped_refptr<base::SingleThreadTaskRunner> pump_task_runner_; | 122 scoped_refptr<base::SingleThreadTaskRunner> pump_task_runner_; |
| 46 | 123 |
| 47 std::unique_ptr<AudioSource> audio_source_; | 124 std::unique_ptr<AudioSource> audio_source_; |
| 48 std::unique_ptr<AudioEncoder> audio_encoder_; | 125 std::unique_ptr<AudioEncoder> audio_encoder_; |
| 49 | 126 |
| 50 bool enabled_; | 127 bool enabled_; |
| 51 | 128 |
| 52 // Number of bytes in the queue that have been encoded but haven't been sent | 129 // Number of bytes in the queue that have been encoded but haven't been sent |
| 53 // yet. | 130 // yet. |
| 54 int bytes_pending_; | 131 int bytes_pending_; |
| 55 | 132 |
| 133 std::unique_ptr<media::ChannelMixer> mixer_ = nullptr; | |
|
joedow
2017/05/26 16:01:50
No need to assign nullptr here since unique_ptr is
Hzj_jie
2017/05/26 20:08:03
Done.
| |
| 134 media::ChannelLayout last_input_layout_ = media::CHANNEL_LAYOUT_NONE; | |
| 135 | |
| 56 DISALLOW_COPY_AND_ASSIGN(Core); | 136 DISALLOW_COPY_AND_ASSIGN(Core); |
| 57 }; | 137 }; |
| 58 | 138 |
| 59 AudioPump::Core::Core(base::WeakPtr<AudioPump> pump, | 139 AudioPump::Core::Core(base::WeakPtr<AudioPump> pump, |
| 60 std::unique_ptr<AudioSource> audio_source, | 140 std::unique_ptr<AudioSource> audio_source, |
| 61 std::unique_ptr<AudioEncoder> audio_encoder) | 141 std::unique_ptr<AudioEncoder> audio_encoder) |
| 62 : pump_(pump), | 142 : pump_(pump), |
| 63 pump_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 143 pump_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 64 audio_source_(std::move(audio_source)), | 144 audio_source_(std::move(audio_source)), |
| 65 audio_encoder_(std::move(audio_encoder)), | 145 audio_encoder_(std::move(audio_encoder)), |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 94 | 174 |
| 95 void AudioPump::Core::EncodeAudioPacket(std::unique_ptr<AudioPacket> packet) { | 175 void AudioPump::Core::EncodeAudioPacket(std::unique_ptr<AudioPacket> packet) { |
| 96 DCHECK(thread_checker_.CalledOnValidThread()); | 176 DCHECK(thread_checker_.CalledOnValidThread()); |
| 97 DCHECK(packet); | 177 DCHECK(packet); |
| 98 | 178 |
| 99 int max_buffered_bytes = | 179 int max_buffered_bytes = |
| 100 audio_encoder_->GetBitrate() * kMaxBufferedIntervalMs / 1000 / 8; | 180 audio_encoder_->GetBitrate() * kMaxBufferedIntervalMs / 1000 / 8; |
| 101 if (!enabled_ || bytes_pending_ > max_buffered_bytes) | 181 if (!enabled_ || bytes_pending_ > max_buffered_bytes) |
| 102 return; | 182 return; |
| 103 | 183 |
| 184 if (packet->channels() > 2) { | |
| 185 packet = Downmix(std::move(packet)); | |
| 186 } | |
| 187 | |
| 104 std::unique_ptr<AudioPacket> encoded_packet = | 188 std::unique_ptr<AudioPacket> encoded_packet = |
| 105 audio_encoder_->Encode(std::move(packet)); | 189 audio_encoder_->Encode(std::move(packet)); |
| 106 | 190 |
| 107 // The audio encoder returns a null audio packet if there's no audio to send. | 191 // The audio encoder returns a null audio packet if there's no audio to send. |
| 108 if (!encoded_packet) | 192 if (!encoded_packet) |
| 109 return; | 193 return; |
| 110 | 194 |
| 111 int packet_size = encoded_packet->ByteSize(); | 195 int packet_size = encoded_packet->ByteSize(); |
| 112 bytes_pending_ += packet_size; | 196 bytes_pending_ += packet_size; |
| 113 | 197 |
| 114 pump_task_runner_->PostTask( | 198 pump_task_runner_->PostTask( |
| 115 FROM_HERE, base::Bind(&AudioPump::SendAudioPacket, pump_, | 199 FROM_HERE, base::Bind(&AudioPump::SendAudioPacket, pump_, |
| 116 base::Passed(&encoded_packet), packet_size)); | 200 base::Passed(&encoded_packet), packet_size)); |
| 117 } | 201 } |
| 118 | 202 |
| 203 std::unique_ptr<AudioPacket> AudioPump::Core::Downmix( | |
| 204 std::unique_ptr<AudioPacket> packet) { | |
| 205 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 206 DCHECK(packet); | |
| 207 using namespace media; | |
| 208 if (packet->data_size() != 1 || | |
| 209 packet->data(0).empty() || | |
| 210 packet->bytes_per_sample() != AudioPacket::BYTES_PER_SAMPLE_2) { | |
| 211 return packet; | |
| 212 } | |
| 213 const ChannelLayout input_layout = RetrieveLayout(*packet); | |
| 214 if (input_layout == CHANNEL_LAYOUT_UNSUPPORTED || | |
| 215 input_layout == CHANNEL_LAYOUT_MONO || | |
| 216 input_layout == CHANNEL_LAYOUT_STEREO) { | |
| 217 return packet; | |
| 218 } | |
| 219 | |
| 220 if (!mixer_ || last_input_layout_ != input_layout) { | |
| 221 last_input_layout_ = input_layout; | |
| 222 mixer_ = base::MakeUnique<ChannelMixer>( | |
| 223 input_layout, CHANNEL_LAYOUT_STEREO); | |
| 224 } | |
| 225 | |
| 226 std::unique_ptr<AudioBus> input = ToAudioBus(*packet); | |
| 227 if (!input) { | |
| 228 return packet; | |
| 229 } | |
| 230 std::unique_ptr<AudioBus> output = AudioBus::Create(2, input->frames()); | |
|
joedow
2017/05/26 16:01:50
Can you replace the magic '2' with AudioPacket::CH
Hzj_jie
2017/05/26 20:08:03
Done.
| |
| 231 mixer_->Transform(input.get(), output.get()); | |
| 232 | |
| 233 std::unique_ptr<AudioPacket> result = FromAudioBus(*output); | |
| 234 DCHECK(result); | |
|
joedow
2017/05/26 16:01:50
I don't think this DCHECK is needed here as the ne
Hzj_jie
2017/05/26 20:08:03
Done.
| |
| 235 result->set_encoding(AudioPacket::ENCODING_RAW); | |
| 236 result->set_sampling_rate(packet->sampling_rate()); | |
| 237 result->set_bytes_per_sample(packet->bytes_per_sample()); | |
| 238 result->set_channels(AudioPacket::CHANNELS_STEREO); | |
| 239 return result; | |
| 240 } | |
| 241 | |
| 119 AudioPump::AudioPump( | 242 AudioPump::AudioPump( |
| 120 scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner, | 243 scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner, |
| 121 std::unique_ptr<AudioSource> audio_source, | 244 std::unique_ptr<AudioSource> audio_source, |
| 122 std::unique_ptr<AudioEncoder> audio_encoder, | 245 std::unique_ptr<AudioEncoder> audio_encoder, |
| 123 AudioStub* audio_stub) | 246 AudioStub* audio_stub) |
| 124 : audio_task_runner_(audio_task_runner), | 247 : audio_task_runner_(audio_task_runner), |
| 125 audio_stub_(audio_stub), | 248 audio_stub_(audio_stub), |
| 126 weak_factory_(this) { | 249 weak_factory_(this) { |
| 127 DCHECK(audio_stub_); | 250 DCHECK(audio_stub_); |
| 128 | 251 |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 157 } | 280 } |
| 158 | 281 |
| 159 void AudioPump::OnPacketSent(int size) { | 282 void AudioPump::OnPacketSent(int size) { |
| 160 audio_task_runner_->PostTask( | 283 audio_task_runner_->PostTask( |
| 161 FROM_HERE, | 284 FROM_HERE, |
| 162 base::Bind(&Core::OnPacketSent, base::Unretained(core_.get()), size)); | 285 base::Bind(&Core::OnPacketSent, base::Unretained(core_.get()), size)); |
| 163 } | 286 } |
| 164 | 287 |
| 165 } // namespace protocol | 288 } // namespace protocol |
| 166 } // namespace remoting | 289 } // namespace remoting |
| OLD | NEW |