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

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

Powered by Google App Engine
This is Rietveld 408576698