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

Side by Side Diff: webrtc/audio/audio_send_stream.cc

Issue 2705093002: Injectable audio encoders: WebRtcVoiceEngine and company (Closed)
Patch Set: Moved encoder creation up into AudioSendStream, bypassing most of Channel. Created 3 years, 9 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 /* 1 /*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #include "webrtc/audio/audio_send_stream.h" 11 #include "webrtc/audio/audio_send_stream.h"
12 12
13 #include <string> 13 #include <string>
14 #include <utility>
14 15
15 #include "webrtc/audio/audio_state.h" 16 #include "webrtc/audio/audio_state.h"
16 #include "webrtc/audio/conversion.h" 17 #include "webrtc/audio/conversion.h"
17 #include "webrtc/audio/scoped_voe_interface.h" 18 #include "webrtc/audio/scoped_voe_interface.h"
18 #include "webrtc/base/checks.h" 19 #include "webrtc/base/checks.h"
19 #include "webrtc/base/event.h" 20 #include "webrtc/base/event.h"
20 #include "webrtc/base/logging.h" 21 #include "webrtc/base/logging.h"
21 #include "webrtc/base/task_queue.h" 22 #include "webrtc/base/task_queue.h"
23 #include "webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.h"
22 #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" 24 #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
23 #include "webrtc/modules/congestion_controller/include/congestion_controller.h" 25 #include "webrtc/modules/congestion_controller/include/congestion_controller.h"
24 #include "webrtc/modules/pacing/paced_sender.h" 26 #include "webrtc/modules/pacing/paced_sender.h"
25 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" 27 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
26 #include "webrtc/voice_engine/channel_proxy.h" 28 #include "webrtc/voice_engine/channel_proxy.h"
27 #include "webrtc/voice_engine/include/voe_base.h" 29 #include "webrtc/voice_engine/include/voe_base.h"
28 #include "webrtc/voice_engine/include/voe_volume_control.h" 30 #include "webrtc/voice_engine/include/voe_volume_control.h"
29 #include "webrtc/voice_engine/voice_engine_impl.h" 31 #include "webrtc/voice_engine/voice_engine_impl.h"
30 32
31 namespace webrtc { 33 namespace webrtc {
32 34
33 namespace {
34
35 constexpr char kOpusCodecName[] = "opus";
36
37 bool IsCodec(const webrtc::CodecInst& codec, const char* ref_name) {
38 return (STR_CASE_CMP(codec.plname, ref_name) == 0);
39 }
40 } // namespace
41
42 namespace internal { 35 namespace internal {
43 AudioSendStream::AudioSendStream( 36 AudioSendStream::AudioSendStream(
44 const webrtc::AudioSendStream::Config& config, 37 const webrtc::AudioSendStream::Config& config,
45 const rtc::scoped_refptr<webrtc::AudioState>& audio_state, 38 const rtc::scoped_refptr<webrtc::AudioState>& audio_state,
46 rtc::TaskQueue* worker_queue, 39 rtc::TaskQueue* worker_queue,
47 PacketRouter* packet_router, 40 PacketRouter* packet_router,
48 CongestionController* congestion_controller, 41 CongestionController* congestion_controller,
49 BitrateAllocator* bitrate_allocator, 42 BitrateAllocator* bitrate_allocator,
50 RtcEventLog* event_log, 43 RtcEventLog* event_log,
51 RtcpRttStats* rtcp_rtt_stats) 44 RtcpRttStats* rtcp_rtt_stats)
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 stats.packets_sent = call_stats.packetsSent; 156 stats.packets_sent = call_stats.packetsSent;
164 // RTT isn't known until a RTCP report is received. Until then, VoiceEngine 157 // RTT isn't known until a RTCP report is received. Until then, VoiceEngine
165 // returns 0 to indicate an error value. 158 // returns 0 to indicate an error value.
166 if (call_stats.rttMs > 0) { 159 if (call_stats.rttMs > 0) {
167 stats.rtt_ms = call_stats.rttMs; 160 stats.rtt_ms = call_stats.rttMs;
168 } 161 }
169 // TODO(solenberg): [was ajm]: Re-enable this metric once we have a reliable 162 // TODO(solenberg): [was ajm]: Re-enable this metric once we have a reliable
170 // implementation. 163 // implementation.
171 stats.aec_quality_min = -1; 164 stats.aec_quality_min = -1;
172 165
173 webrtc::CodecInst codec_inst = {0}; 166 const auto& spec = config_.send_codec_spec;
174 if (channel_proxy_->GetSendCodec(&codec_inst)) { 167 if (config_.send_codec_spec.format.name != "") {
the sun 2017/03/16 08:48:19 Do you have a separate CL lined up to clean out th
kwiberg-webrtc 2017/03/01 12:26:47 Is this a test for whether the format is "empty"?
the sun 2017/03/02 20:37:24 nit: use spec.format.name
ossu 2017/03/02 20:43:27 Sure thing!
175 RTC_DCHECK_NE(codec_inst.pltype, -1); 168 stats.codec_name = spec.format.name;
176 stats.codec_name = codec_inst.plname; 169 stats.codec_payload_type = rtc::Optional<int>(spec.payload_type);
177 stats.codec_payload_type = rtc::Optional<int>(codec_inst.pltype);
178 170
179 // Get data from the last remote RTCP report. 171 // Get data from the last remote RTCP report.
180 for (const auto& block : channel_proxy_->GetRemoteRTCPReportBlocks()) { 172 for (const auto& block : channel_proxy_->GetRemoteRTCPReportBlocks()) {
181 // Lookup report for send ssrc only. 173 // Lookup report for send ssrc only.
182 if (block.source_SSRC == stats.local_ssrc) { 174 if (block.source_SSRC == stats.local_ssrc) {
183 stats.packets_lost = block.cumulative_num_packets_lost; 175 stats.packets_lost = block.cumulative_num_packets_lost;
184 stats.fraction_lost = Q8ToFloat(block.fraction_lost); 176 stats.fraction_lost = Q8ToFloat(block.fraction_lost);
185 stats.ext_seqnum = block.extended_highest_sequence_number; 177 stats.ext_seqnum = block.extended_highest_sequence_number;
186 // Convert samples to milliseconds. 178 // Convert timestamps to milliseconds.
187 if (codec_inst.plfreq / 1000 > 0) { 179 if (spec.format.clockrate_hz / 1000 > 0) {
188 stats.jitter_ms = 180 stats.jitter_ms =
189 block.interarrival_jitter / (codec_inst.plfreq / 1000); 181 block.interarrival_jitter / (spec.format.clockrate_hz / 1000);
190 } 182 }
191 break; 183 break;
192 } 184 }
193 } 185 }
194 } 186 }
195 187
196 // Local speech level. 188 // Local speech level.
197 { 189 {
198 ScopedVoEInterface<VoEVolumeControl> volume(voice_engine()); 190 ScopedVoEInterface<VoEVolumeControl> volume(voice_engine());
199 unsigned int level = 0; 191 unsigned int level = 0;
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 VoiceEngine* AudioSendStream::voice_engine() const { 259 VoiceEngine* AudioSendStream::voice_engine() const {
268 internal::AudioState* audio_state = 260 internal::AudioState* audio_state =
269 static_cast<internal::AudioState*>(audio_state_.get()); 261 static_cast<internal::AudioState*>(audio_state_.get());
270 VoiceEngine* voice_engine = audio_state->voice_engine(); 262 VoiceEngine* voice_engine = audio_state->voice_engine();
271 RTC_DCHECK(voice_engine); 263 RTC_DCHECK(voice_engine);
272 return voice_engine; 264 return voice_engine;
273 } 265 }
274 266
275 // Apply current codec settings to a single voe::Channel used for sending. 267 // Apply current codec settings to a single voe::Channel used for sending.
276 bool AudioSendStream::SetupSendCodec() { 268 bool AudioSendStream::SetupSendCodec() {
277 // Disable VAD and FEC unless we know the other side wants them. 269 // TODO(ossu): This check is due to some Call tests creating AudioSendStreams
278 channel_proxy_->SetVADStatus(false); 270 // without a reasonable config.
the sun 2017/03/16 08:48:19 Is that because they're explicitly setting up the
ossu 2017/03/20 18:19:48 After working through it, I realized streams getti
279 channel_proxy_->SetCodecFECStatus(false); 271 if (!config_.encoder_factory || config_.send_codec_spec.format.name == "")
280 272 return false;
281 // We disable audio network adaptor here. This will on one hand make sure that
282 // audio network adaptor is disabled by default, and on the other allow audio
283 // network adaptor to be reconfigured, since SetReceiverFrameLengthRange can
284 // be only called when audio network adaptor is disabled.
285 channel_proxy_->DisableAudioNetworkAdaptor();
286 273
287 const auto& send_codec_spec = config_.send_codec_spec; 274 const auto& send_codec_spec = config_.send_codec_spec;
275 std::unique_ptr<AudioEncoder> encoder =
276 config_.encoder_factory->MakeAudioEncoder(send_codec_spec.payload_type,
277 send_codec_spec.format);
288 278
289 // We set the codec first, since the below extra configuration is only applied 279 if (!encoder) {
the sun 2017/03/16 08:48:19 Any chance we could make this a CHECK or DCHECK go
ossu 2017/03/20 18:19:48 I've rephrased it and made it log an error instead
290 // to the "current" codec. 280 LOG(LS_WARNING) << "Unknown format " << send_codec_spec.format;
291 281 return false;
292 // If codec is already configured, we do not it again.
293 // TODO(minyue): check if this check is really needed, or can we move it into
294 // |codec->SetSendCodec|.
295 webrtc::CodecInst current_codec = {0};
296 if (!channel_proxy_->GetSendCodec(&current_codec) ||
297 (send_codec_spec.codec_inst != current_codec)) {
298 if (!channel_proxy_->SetSendCodec(send_codec_spec.codec_inst)) {
299 LOG(LS_WARNING) << "SetSendCodec() failed.";
300 return false;
301 }
302 } 282 }
303 283
304 // Codec internal FEC. Treat any failure as fatal internal error. 284 // If a bitrate has been specified for the codec, use it over the
305 if (send_codec_spec.enable_codec_fec) { 285 // codec's default.
306 if (!channel_proxy_->SetCodecFECStatus(true)) { 286 if (send_codec_spec.target_bitrate_bps) {
307 LOG(LS_WARNING) << "SetCodecFECStatus() failed."; 287 encoder->OnReceivedTargetAudioBitrate(*send_codec_spec.target_bitrate_bps);
308 return false;
309 }
310 }
311
312 // DTX and maxplaybackrate are only set if current codec is Opus.
313 if (IsCodec(send_codec_spec.codec_inst, kOpusCodecName)) {
314 if (!channel_proxy_->SetOpusDtx(send_codec_spec.enable_opus_dtx)) {
315 LOG(LS_WARNING) << "SetOpusDtx() failed.";
316 return false;
317 }
318
319 // If opus_max_playback_rate <= 0, the default maximum playback rate
320 // (48 kHz) will be used.
321 if (send_codec_spec.opus_max_playback_rate > 0) {
322 if (!channel_proxy_->SetOpusMaxPlaybackRate(
323 send_codec_spec.opus_max_playback_rate)) {
324 LOG(LS_WARNING) << "SetOpusMaxPlaybackRate() failed.";
325 return false;
326 }
327 }
328
329 if (config_.audio_network_adaptor_config) {
330 // Audio network adaptor is only allowed for Opus currently.
331 // |SetReceiverFrameLengthRange| needs to be called before
332 // |EnableAudioNetworkAdaptor|.
333 channel_proxy_->SetReceiverFrameLengthRange(send_codec_spec.min_ptime_ms,
334 send_codec_spec.max_ptime_ms);
335 channel_proxy_->EnableAudioNetworkAdaptor(
336 *config_.audio_network_adaptor_config);
337 LOG(LS_INFO) << "Audio network adaptor enabled on SSRC "
338 << config_.rtp.ssrc;
339 }
340 } 288 }
341 289
342 // Set the CN payloadtype and the VAD status. 290 // Set the CN payloadtype and the VAD status.
the sun 2017/03/16 08:48:19 Comment is a bit off.
ossu 2017/03/20 18:19:48 Acknowledged.
343 if (send_codec_spec.cng_payload_type != -1) { 291 if (send_codec_spec.cng_payload_type != -1) {
344 // The CN payload type for 8000 Hz clockrate is fixed at 13. 292 AudioEncoderCng::Config config;
345 if (send_codec_spec.cng_plfreq != 8000) { 293 config.num_channels = encoder->NumChannels();
346 webrtc::PayloadFrequencies cn_freq; 294 config.payload_type = send_codec_spec.cng_payload_type;
347 switch (send_codec_spec.cng_plfreq) { 295 config.speech_encoder = std::move(encoder);
348 case 16000: 296 config.vad_mode = Vad::kVadNormal;
349 cn_freq = webrtc::kFreq16000Hz; 297 encoder =
350 break; 298 std::unique_ptr<AudioEncoder>(new AudioEncoderCng(std::move(config)));
kwiberg-webrtc 2017/03/01 12:26:47 encoder.reset(...) would be shorter here.
ossu 2017/03/02 01:30:28 Yupp! Will change.
351 case 32000: 299 }
352 cn_freq = webrtc::kFreq32000Hz;
353 break;
354 default:
355 RTC_NOTREACHED();
356 return false;
357 }
358 if (!channel_proxy_->SetSendCNPayloadType(
359 send_codec_spec.cng_payload_type, cn_freq)) {
360 LOG(LS_WARNING) << "SetSendCNPayloadType() failed.";
361 // TODO(ajm): This failure condition will be removed from VoE.
362 // Restore the return here when we update to a new enough webrtc.
363 //
364 // Not returning false because the SetSendCNPayloadType will fail if
365 // the channel is already sending.
366 // This can happen if the remote description is applied twice, for
367 // example in the case of ROAP on top of JSEP, where both side will
368 // send the offer.
369 }
370 }
371 300
372 // Only turn on VAD if we have a CN payload type that matches the 301 channel_proxy_->SetEncoder(send_codec_spec.payload_type, std::move(encoder));
373 // clockrate for the codec we are going to use. 302
374 if (send_codec_spec.cng_plfreq == send_codec_spec.codec_inst.plfreq && 303 // TODO(ossu): The encoder interface wants an RtcEventLogProxy and a Clock,
the sun 2017/03/16 08:48:19 We've decided to use the webrtc/base/timeutils.h A
375 send_codec_spec.codec_inst.channels == 1) { 304 // both of which are in Channel. Solve this!
376 // TODO(minyue): If CN frequency == 48000 Hz is allowed, consider the 305 if (config_.audio_network_adaptor_config) {
377 // interaction between VAD and Opus FEC. 306 // Audio network adaptor is only allowed for Opus currently.
kwiberg-webrtc 2017/03/01 12:26:47 This comment doesn't appear to have any correspond
ossu 2017/03/02 01:30:28 Hmm... I agree that it doesn't describe the code t
378 if (!channel_proxy_->SetVADStatus(true)) { 307 channel_proxy_->EnableAudioNetworkAdaptor(
the sun 2017/03/02 20:37:24 Is it possible to avoid this call to voe::Channel
ossu 2017/03/02 20:43:27 I'll look into it. The AudioEncoder version of thi
ossu 2017/03/20 18:19:48 Turns out avoiding the call through ChannelProxy h
379 LOG(LS_WARNING) << "SetVADStatus() failed."; 308 *config_.audio_network_adaptor_config);
380 return false; 309 LOG(LS_INFO) << "Audio network adaptor enabled on SSRC "
381 } 310 << config_.rtp.ssrc;
382 }
383 } 311 }
312
384 return true; 313 return true;
385 } 314 }
386 315
387 } // namespace internal 316 } // namespace internal
388 } // namespace webrtc 317 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698