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

Side by Side Diff: remoting/protocol/audio_pump.cc

Issue 2903153004: [Chromoting] Implement down mixing in AudioPump (Closed)
Patch Set: Created 3 years, 7 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 unified diff | Download patch
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698