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

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

Issue 2903153004: [Chromoting] Implement down mixing in AudioPump (Closed)
Patch Set: Resolve review comments Created 3 years, 6 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();
chcunningham 2017/06/08 16:39:45 I think this calculation could go sideways if you
Hzj_jie 2017/06/08 19:07:48 We do not change the dwChannelMask returned by Get
30 }
31
32 std::unique_ptr<media::AudioBus> AudioPacketToAudioBus(
33 const remoting::AudioPacket& packet) {
34 const int frame_count = CalculateFrameCount(packet);
35 DCHECK_GT(frame_count, 0);
36 std::unique_ptr<media::AudioBus> result =
37 media::AudioBus::Create(packet.channels(), frame_count);
38 result->FromInterleaved<media::SignedInt16SampleTypeTraits>(
39 reinterpret_cast<const int16_t*>(packet.data(0).data()), frame_count);
40 return result;
41 }
42
43 std::unique_ptr<remoting::AudioPacket> AudioBusToAudioPacket(
44 const media::AudioBus& packet) {
45 std::unique_ptr<remoting::AudioPacket> result =
46 base::MakeUnique<remoting::AudioPacket>();
47 result->add_data()->resize(
48 packet.channels() * packet.frames() * sizeof(int16_t));
49 packet.ToInterleaved<media::SignedInt16SampleTypeTraits>(
50 packet.frames(),
51 reinterpret_cast<int16_t*>(&(result->mutable_data(0)->at(0))));
52 result->set_encoding(remoting::AudioPacket::ENCODING_RAW);
53 result->set_channels(
54 static_cast<remoting::AudioPacket::Channels>(packet.channels()));
55 result->set_bytes_per_sample(remoting::AudioPacket::BYTES_PER_SAMPLE_2);
56 return result;
57 }
58
59 media::ChannelLayout RetrieveLayout(const remoting::AudioPacket& packet) {
60 // This switch should match AudioPacket::Channels enum in audio.proto.
61 switch (packet.channels()) {
62 case remoting::AudioPacket::CHANNELS_INVALID:
63 return media::CHANNEL_LAYOUT_UNSUPPORTED;
64 case remoting::AudioPacket::CHANNELS_MONO:
65 return media::CHANNEL_LAYOUT_MONO;
66 case remoting::AudioPacket::CHANNELS_STEREO:
67 return media::CHANNEL_LAYOUT_STEREO;
68 case remoting::AudioPacket::CHANNELS_SURROUND:
69 return media::CHANNEL_LAYOUT_SURROUND;
70 case remoting::AudioPacket::CHANNELS_4_0:
71 return media::CHANNEL_LAYOUT_4_0;
72 case remoting::AudioPacket::CHANNELS_4_1:
73 return media::CHANNEL_LAYOUT_4_1;
74 case remoting::AudioPacket::CHANNELS_5_1:
75 return media::CHANNEL_LAYOUT_5_1;
76 case remoting::AudioPacket::CHANNELS_6_1:
77 return media::CHANNEL_LAYOUT_6_1;
78 case remoting::AudioPacket::CHANNELS_7_1:
79 return media::CHANNEL_LAYOUT_7_1;
80 }
81 NOTREACHED() << "Invalid AudioPacket::Channels";
82 return media::CHANNEL_LAYOUT_UNSUPPORTED;
83 }
84
85 } // namespace
86
20 namespace remoting { 87 namespace remoting {
21 namespace protocol { 88 namespace protocol {
22 89
23 // Limit the data stored in the pending send buffers to 250ms. 90 // Limit the data stored in the pending send buffers to 250ms.
24 const int kMaxBufferedIntervalMs = 250; 91 const int kMaxBufferedIntervalMs = 250;
25 92
26 class AudioPump::Core { 93 class AudioPump::Core {
27 public: 94 public:
28 Core(base::WeakPtr<AudioPump> pump, 95 Core(base::WeakPtr<AudioPump> pump,
29 std::unique_ptr<AudioSource> audio_source, 96 std::unique_ptr<AudioSource> audio_source,
30 std::unique_ptr<AudioEncoder> audio_encoder); 97 std::unique_ptr<AudioEncoder> audio_encoder);
31 ~Core(); 98 ~Core();
32 99
33 void Start(); 100 void Start();
34 void Pause(bool pause); 101 void Pause(bool pause);
35 102
36 void OnPacketSent(int size); 103 void OnPacketSent(int size);
37 104
38 private: 105 private:
106 std::unique_ptr<AudioPacket> Downmix(std::unique_ptr<AudioPacket> packet);
107
39 void EncodeAudioPacket(std::unique_ptr<AudioPacket> packet); 108 void EncodeAudioPacket(std::unique_ptr<AudioPacket> packet);
40 109
41 base::ThreadChecker thread_checker_; 110 base::ThreadChecker thread_checker_;
42 111
43 base::WeakPtr<AudioPump> pump_; 112 base::WeakPtr<AudioPump> pump_;
44 113
45 scoped_refptr<base::SingleThreadTaskRunner> pump_task_runner_; 114 scoped_refptr<base::SingleThreadTaskRunner> pump_task_runner_;
46 115
47 std::unique_ptr<AudioSource> audio_source_; 116 std::unique_ptr<AudioSource> audio_source_;
48 std::unique_ptr<AudioEncoder> audio_encoder_; 117 std::unique_ptr<AudioEncoder> audio_encoder_;
49 118
50 bool enabled_; 119 bool enabled_;
51 120
52 // Number of bytes in the queue that have been encoded but haven't been sent 121 // Number of bytes in the queue that have been encoded but haven't been sent
53 // yet. 122 // yet.
54 int bytes_pending_; 123 int bytes_pending_;
55 124
125 std::unique_ptr<media::ChannelMixer> mixer_;
126 media::ChannelLayout mixer_input_layout_ = media::CHANNEL_LAYOUT_NONE;
127
56 DISALLOW_COPY_AND_ASSIGN(Core); 128 DISALLOW_COPY_AND_ASSIGN(Core);
57 }; 129 };
58 130
59 AudioPump::Core::Core(base::WeakPtr<AudioPump> pump, 131 AudioPump::Core::Core(base::WeakPtr<AudioPump> pump,
60 std::unique_ptr<AudioSource> audio_source, 132 std::unique_ptr<AudioSource> audio_source,
61 std::unique_ptr<AudioEncoder> audio_encoder) 133 std::unique_ptr<AudioEncoder> audio_encoder)
62 : pump_(pump), 134 : pump_(pump),
63 pump_task_runner_(base::ThreadTaskRunnerHandle::Get()), 135 pump_task_runner_(base::ThreadTaskRunnerHandle::Get()),
64 audio_source_(std::move(audio_source)), 136 audio_source_(std::move(audio_source)),
65 audio_encoder_(std::move(audio_encoder)), 137 audio_encoder_(std::move(audio_encoder)),
(...skipping 25 matching lines...) Expand all
91 bytes_pending_ -= size; 163 bytes_pending_ -= size;
92 DCHECK_GE(bytes_pending_, 0); 164 DCHECK_GE(bytes_pending_, 0);
93 } 165 }
94 166
95 void AudioPump::Core::EncodeAudioPacket(std::unique_ptr<AudioPacket> packet) { 167 void AudioPump::Core::EncodeAudioPacket(std::unique_ptr<AudioPacket> packet) {
96 DCHECK(thread_checker_.CalledOnValidThread()); 168 DCHECK(thread_checker_.CalledOnValidThread());
97 DCHECK(packet); 169 DCHECK(packet);
98 170
99 int max_buffered_bytes = 171 int max_buffered_bytes =
100 audio_encoder_->GetBitrate() * kMaxBufferedIntervalMs / 1000 / 8; 172 audio_encoder_->GetBitrate() * kMaxBufferedIntervalMs / 1000 / 8;
101 if (!enabled_ || bytes_pending_ > max_buffered_bytes) 173 if (!enabled_ || bytes_pending_ > max_buffered_bytes) {
102 return; 174 return;
175 }
176
177 if (packet->channels() > AudioPacket::CHANNELS_STEREO) {
178 packet = Downmix(std::move(packet));
179 }
103 180
104 std::unique_ptr<AudioPacket> encoded_packet = 181 std::unique_ptr<AudioPacket> encoded_packet =
105 audio_encoder_->Encode(std::move(packet)); 182 audio_encoder_->Encode(std::move(packet));
106 183
107 // The audio encoder returns a null audio packet if there's no audio to send. 184 // The audio encoder returns a null audio packet if there's no audio to send.
108 if (!encoded_packet) 185 if (!encoded_packet) {
109 return; 186 return;
187 }
110 188
111 int packet_size = encoded_packet->ByteSize(); 189 int packet_size = encoded_packet->ByteSize();
112 bytes_pending_ += packet_size; 190 bytes_pending_ += packet_size;
113 191
114 pump_task_runner_->PostTask( 192 pump_task_runner_->PostTask(
115 FROM_HERE, base::Bind(&AudioPump::SendAudioPacket, pump_, 193 FROM_HERE, base::Bind(&AudioPump::SendAudioPacket, pump_,
116 base::Passed(&encoded_packet), packet_size)); 194 base::Passed(&encoded_packet), packet_size));
117 } 195 }
118 196
197 std::unique_ptr<AudioPacket> AudioPump::Core::Downmix(
198 std::unique_ptr<AudioPacket> packet) {
199 DCHECK(thread_checker_.CalledOnValidThread());
200 DCHECK(packet);
201 DCHECK_EQ(packet->data_size(), 1);
202 DCHECK_EQ(packet->bytes_per_sample(), AudioPacket::BYTES_PER_SAMPLE_2);
203
204 const media::ChannelLayout input_layout = RetrieveLayout(*packet);
205 DCHECK_NE(input_layout, media::CHANNEL_LAYOUT_UNSUPPORTED);
206 DCHECK_NE(input_layout, media::CHANNEL_LAYOUT_MONO);
207 DCHECK_NE(input_layout, media::CHANNEL_LAYOUT_STEREO);
208
209 if (!mixer_ || mixer_input_layout_ != input_layout) {
210 mixer_input_layout_ = input_layout;
211 mixer_ = base::MakeUnique<media::ChannelMixer>(
212 input_layout, media::CHANNEL_LAYOUT_STEREO);
213 }
214
215 std::unique_ptr<media::AudioBus> input = AudioPacketToAudioBus(*packet);
216 DCHECK(input);
217 std::unique_ptr<media::AudioBus> output =
218 media::AudioBus::Create(AudioPacket::CHANNELS_STEREO, input->frames());
219 mixer_->Transform(input.get(), output.get());
220
221 std::unique_ptr<AudioPacket> result = AudioBusToAudioPacket(*output);
222 result->set_sampling_rate(packet->sampling_rate());
223 return result;
224 }
225
119 AudioPump::AudioPump( 226 AudioPump::AudioPump(
120 scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner, 227 scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner,
121 std::unique_ptr<AudioSource> audio_source, 228 std::unique_ptr<AudioSource> audio_source,
122 std::unique_ptr<AudioEncoder> audio_encoder, 229 std::unique_ptr<AudioEncoder> audio_encoder,
123 AudioStub* audio_stub) 230 AudioStub* audio_stub)
124 : audio_task_runner_(audio_task_runner), 231 : audio_task_runner_(audio_task_runner),
125 audio_stub_(audio_stub), 232 audio_stub_(audio_stub),
126 weak_factory_(this) { 233 weak_factory_(this) {
127 DCHECK(audio_stub_); 234 DCHECK(audio_stub_);
128 235
(...skipping 28 matching lines...) Expand all
157 } 264 }
158 265
159 void AudioPump::OnPacketSent(int size) { 266 void AudioPump::OnPacketSent(int size) {
160 audio_task_runner_->PostTask( 267 audio_task_runner_->PostTask(
161 FROM_HERE, 268 FROM_HERE,
162 base::Bind(&Core::OnPacketSent, base::Unretained(core_.get()), size)); 269 base::Bind(&Core::OnPacketSent, base::Unretained(core_.get()), size));
163 } 270 }
164 271
165 } // namespace protocol 272 } // namespace protocol
166 } // namespace remoting 273 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698