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

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

Issue 2903153004: [Chromoting] Implement down mixing in AudioPump (Closed)
Patch Set: Resovle 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
« no previous file with comments | « remoting/protocol/audio_pump.h ('k') | remoting/protocol/audio_pump_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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();
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) {
Sergey Ulanov 2017/06/07 06:24:59 Do we need this check given that Downmix() already
Hzj_jie 2017/06/07 20:27:18 Done. I have removed the if-condition in Downmix()
178 packet = Downmix(std::move(packet));
Sergey Ulanov 2017/06/07 06:24:59 Downmix() currently may return nullptr, but this c
Hzj_jie 2017/06/07 20:27:18 Done.
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)
Sergey Ulanov 2017/06/07 06:24:59 please add {} here for consistency
Hzj_jie 2017/06/07 20:27:18 Done.
109 return; 186 return;
110 187
111 int packet_size = encoded_packet->ByteSize(); 188 int packet_size = encoded_packet->ByteSize();
112 bytes_pending_ += packet_size; 189 bytes_pending_ += packet_size;
113 190
114 pump_task_runner_->PostTask( 191 pump_task_runner_->PostTask(
115 FROM_HERE, base::Bind(&AudioPump::SendAudioPacket, pump_, 192 FROM_HERE, base::Bind(&AudioPump::SendAudioPacket, pump_,
116 base::Passed(&encoded_packet), packet_size)); 193 base::Passed(&encoded_packet), packet_size));
117 } 194 }
118 195
196 std::unique_ptr<AudioPacket> AudioPump::Core::Downmix(
197 std::unique_ptr<AudioPacket> packet) {
198 DCHECK(thread_checker_.CalledOnValidThread());
199 DCHECK(packet);
200 DCHECK_EQ(packet->data_size(), 1);
201 DCHECK_EQ(packet->bytes_per_sample(), AudioPacket::BYTES_PER_SAMPLE_2);
202
203 const media::ChannelLayout input_layout = RetrieveLayout(*packet);
204 if (input_layout == media::CHANNEL_LAYOUT_UNSUPPORTED) {
205 return nullptr;
206 }
207 if (input_layout == media::CHANNEL_LAYOUT_MONO ||
208 input_layout == media::CHANNEL_LAYOUT_STEREO) {
209 return packet;
210 }
211
212 if (!mixer_ || mixer_input_layout_ != input_layout) {
213 mixer_input_layout_ = input_layout;
214 mixer_ = base::MakeUnique<media::ChannelMixer>(
215 input_layout, media::CHANNEL_LAYOUT_STEREO);
216 }
217
218 std::unique_ptr<media::AudioBus> input = AudioPacketToAudioBus(*packet);
219 if (!input) {
220 return nullptr;
221 }
222 std::unique_ptr<media::AudioBus> output =
223 media::AudioBus::Create(AudioPacket::CHANNELS_STEREO, input->frames());
224 mixer_->Transform(input.get(), output.get());
225
226 std::unique_ptr<AudioPacket> result = AudioBusToAudioPacket(*output);
227 result->set_sampling_rate(packet->sampling_rate());
228 return result;
229 }
230
119 AudioPump::AudioPump( 231 AudioPump::AudioPump(
120 scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner, 232 scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner,
121 std::unique_ptr<AudioSource> audio_source, 233 std::unique_ptr<AudioSource> audio_source,
122 std::unique_ptr<AudioEncoder> audio_encoder, 234 std::unique_ptr<AudioEncoder> audio_encoder,
123 AudioStub* audio_stub) 235 AudioStub* audio_stub)
124 : audio_task_runner_(audio_task_runner), 236 : audio_task_runner_(audio_task_runner),
125 audio_stub_(audio_stub), 237 audio_stub_(audio_stub),
126 weak_factory_(this) { 238 weak_factory_(this) {
127 DCHECK(audio_stub_); 239 DCHECK(audio_stub_);
128 240
(...skipping 28 matching lines...) Expand all
157 } 269 }
158 270
159 void AudioPump::OnPacketSent(int size) { 271 void AudioPump::OnPacketSent(int size) {
160 audio_task_runner_->PostTask( 272 audio_task_runner_->PostTask(
161 FROM_HERE, 273 FROM_HERE,
162 base::Bind(&Core::OnPacketSent, base::Unretained(core_.get()), size)); 274 base::Bind(&Core::OnPacketSent, base::Unretained(core_.get()), size));
163 } 275 }
164 276
165 } // namespace protocol 277 } // namespace protocol
166 } // namespace remoting 278 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/protocol/audio_pump.h ('k') | remoting/protocol/audio_pump_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698