blob: a4a497744126476bff9bffdba99523adeef4ad0a [file] [log] [blame]
Niels Möller530ead42018-10-04 14:28:39 +02001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "audio/channel_send.h"
12
13#include <algorithm>
14#include <map>
15#include <memory>
16#include <string>
17#include <utility>
18#include <vector>
19
20#include "absl/memory/memory.h"
21#include "api/array_view.h"
Benjamin Wright84583f62018-10-04 14:22:34 -070022#include "api/crypto/frameencryptorinterface.h"
Niels Möller530ead42018-10-04 14:28:39 +020023#include "audio/utility/audio_frame_operations.h"
24#include "call/rtp_transport_controller_send_interface.h"
25#include "logging/rtc_event_log/events/rtc_event_audio_playout.h"
26#include "logging/rtc_event_log/rtc_event_log.h"
27#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h"
28#include "modules/pacing/packet_router.h"
29#include "modules/utility/include/process_thread.h"
30#include "rtc_base/checks.h"
31#include "rtc_base/criticalsection.h"
Yves Gerey2e00abc2018-10-05 15:39:24 +020032#include "rtc_base/event.h"
Niels Möller530ead42018-10-04 14:28:39 +020033#include "rtc_base/format_macros.h"
34#include "rtc_base/location.h"
35#include "rtc_base/logging.h"
36#include "rtc_base/rate_limiter.h"
37#include "rtc_base/task_queue.h"
38#include "rtc_base/thread_checker.h"
39#include "rtc_base/timeutils.h"
40#include "system_wrappers/include/field_trial.h"
41#include "system_wrappers/include/metrics.h"
42
43namespace webrtc {
44namespace voe {
45
46namespace {
47
48constexpr int64_t kMaxRetransmissionWindowMs = 1000;
49constexpr int64_t kMinRetransmissionWindowMs = 30;
50
Niels Möller7d76a312018-10-26 12:57:07 +020051MediaTransportEncodedAudioFrame::FrameType
52MediaTransportFrameTypeForWebrtcFrameType(webrtc::FrameType frame_type) {
53 switch (frame_type) {
54 case kAudioFrameSpeech:
55 return MediaTransportEncodedAudioFrame::FrameType::kSpeech;
56 break;
57
58 case kAudioFrameCN:
59 return MediaTransportEncodedAudioFrame::FrameType::
60 kDiscontinuousTransmission;
61 break;
62
63 default:
64 RTC_CHECK(false) << "Unexpected frame type=" << frame_type;
65 break;
66 }
67}
68
Niels Möller530ead42018-10-04 14:28:39 +020069} // namespace
70
71const int kTelephoneEventAttenuationdB = 10;
72
73class TransportFeedbackProxy : public TransportFeedbackObserver {
74 public:
75 TransportFeedbackProxy() : feedback_observer_(nullptr) {
76 pacer_thread_.DetachFromThread();
77 network_thread_.DetachFromThread();
78 }
79
80 void SetTransportFeedbackObserver(
81 TransportFeedbackObserver* feedback_observer) {
82 RTC_DCHECK(thread_checker_.CalledOnValidThread());
83 rtc::CritScope lock(&crit_);
84 feedback_observer_ = feedback_observer;
85 }
86
87 // Implements TransportFeedbackObserver.
88 void AddPacket(uint32_t ssrc,
89 uint16_t sequence_number,
90 size_t length,
91 const PacedPacketInfo& pacing_info) override {
92 RTC_DCHECK(pacer_thread_.CalledOnValidThread());
93 rtc::CritScope lock(&crit_);
94 if (feedback_observer_)
95 feedback_observer_->AddPacket(ssrc, sequence_number, length, pacing_info);
96 }
97
98 void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override {
99 RTC_DCHECK(network_thread_.CalledOnValidThread());
100 rtc::CritScope lock(&crit_);
101 if (feedback_observer_)
102 feedback_observer_->OnTransportFeedback(feedback);
103 }
104
105 private:
106 rtc::CriticalSection crit_;
107 rtc::ThreadChecker thread_checker_;
108 rtc::ThreadChecker pacer_thread_;
109 rtc::ThreadChecker network_thread_;
110 TransportFeedbackObserver* feedback_observer_ RTC_GUARDED_BY(&crit_);
111};
112
113class TransportSequenceNumberProxy : public TransportSequenceNumberAllocator {
114 public:
115 TransportSequenceNumberProxy() : seq_num_allocator_(nullptr) {
116 pacer_thread_.DetachFromThread();
117 }
118
119 void SetSequenceNumberAllocator(
120 TransportSequenceNumberAllocator* seq_num_allocator) {
121 RTC_DCHECK(thread_checker_.CalledOnValidThread());
122 rtc::CritScope lock(&crit_);
123 seq_num_allocator_ = seq_num_allocator;
124 }
125
126 // Implements TransportSequenceNumberAllocator.
127 uint16_t AllocateSequenceNumber() override {
128 RTC_DCHECK(pacer_thread_.CalledOnValidThread());
129 rtc::CritScope lock(&crit_);
130 if (!seq_num_allocator_)
131 return 0;
132 return seq_num_allocator_->AllocateSequenceNumber();
133 }
134
135 private:
136 rtc::CriticalSection crit_;
137 rtc::ThreadChecker thread_checker_;
138 rtc::ThreadChecker pacer_thread_;
139 TransportSequenceNumberAllocator* seq_num_allocator_ RTC_GUARDED_BY(&crit_);
140};
141
142class RtpPacketSenderProxy : public RtpPacketSender {
143 public:
144 RtpPacketSenderProxy() : rtp_packet_sender_(nullptr) {}
145
146 void SetPacketSender(RtpPacketSender* rtp_packet_sender) {
147 RTC_DCHECK(thread_checker_.CalledOnValidThread());
148 rtc::CritScope lock(&crit_);
149 rtp_packet_sender_ = rtp_packet_sender;
150 }
151
152 // Implements RtpPacketSender.
153 void InsertPacket(Priority priority,
154 uint32_t ssrc,
155 uint16_t sequence_number,
156 int64_t capture_time_ms,
157 size_t bytes,
158 bool retransmission) override {
159 rtc::CritScope lock(&crit_);
160 if (rtp_packet_sender_) {
161 rtp_packet_sender_->InsertPacket(priority, ssrc, sequence_number,
162 capture_time_ms, bytes, retransmission);
163 }
164 }
165
166 void SetAccountForAudioPackets(bool account_for_audio) override {
167 RTC_NOTREACHED();
168 }
169
170 private:
171 rtc::ThreadChecker thread_checker_;
172 rtc::CriticalSection crit_;
173 RtpPacketSender* rtp_packet_sender_ RTC_GUARDED_BY(&crit_);
174};
175
176class VoERtcpObserver : public RtcpBandwidthObserver {
177 public:
178 explicit VoERtcpObserver(ChannelSend* owner)
179 : owner_(owner), bandwidth_observer_(nullptr) {}
180 virtual ~VoERtcpObserver() {}
181
182 void SetBandwidthObserver(RtcpBandwidthObserver* bandwidth_observer) {
183 rtc::CritScope lock(&crit_);
184 bandwidth_observer_ = bandwidth_observer;
185 }
186
187 void OnReceivedEstimatedBitrate(uint32_t bitrate) override {
188 rtc::CritScope lock(&crit_);
189 if (bandwidth_observer_) {
190 bandwidth_observer_->OnReceivedEstimatedBitrate(bitrate);
191 }
192 }
193
194 void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
195 int64_t rtt,
196 int64_t now_ms) override {
197 {
198 rtc::CritScope lock(&crit_);
199 if (bandwidth_observer_) {
200 bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, rtt,
201 now_ms);
202 }
203 }
204 // TODO(mflodman): Do we need to aggregate reports here or can we jut send
205 // what we get? I.e. do we ever get multiple reports bundled into one RTCP
206 // report for VoiceEngine?
207 if (report_blocks.empty())
208 return;
209
210 int fraction_lost_aggregate = 0;
211 int total_number_of_packets = 0;
212
213 // If receiving multiple report blocks, calculate the weighted average based
214 // on the number of packets a report refers to.
215 for (ReportBlockList::const_iterator block_it = report_blocks.begin();
216 block_it != report_blocks.end(); ++block_it) {
217 // Find the previous extended high sequence number for this remote SSRC,
218 // to calculate the number of RTP packets this report refers to. Ignore if
219 // we haven't seen this SSRC before.
220 std::map<uint32_t, uint32_t>::iterator seq_num_it =
221 extended_max_sequence_number_.find(block_it->source_ssrc);
222 int number_of_packets = 0;
223 if (seq_num_it != extended_max_sequence_number_.end()) {
224 number_of_packets =
225 block_it->extended_highest_sequence_number - seq_num_it->second;
226 }
227 fraction_lost_aggregate += number_of_packets * block_it->fraction_lost;
228 total_number_of_packets += number_of_packets;
229
230 extended_max_sequence_number_[block_it->source_ssrc] =
231 block_it->extended_highest_sequence_number;
232 }
233 int weighted_fraction_lost = 0;
234 if (total_number_of_packets > 0) {
235 weighted_fraction_lost =
236 (fraction_lost_aggregate + total_number_of_packets / 2) /
237 total_number_of_packets;
238 }
239 owner_->OnUplinkPacketLossRate(weighted_fraction_lost / 255.0f);
240 }
241
242 private:
243 ChannelSend* owner_;
244 // Maps remote side ssrc to extended highest sequence number received.
245 std::map<uint32_t, uint32_t> extended_max_sequence_number_;
246 rtc::CriticalSection crit_;
247 RtcpBandwidthObserver* bandwidth_observer_ RTC_GUARDED_BY(crit_);
248};
249
250class ChannelSend::ProcessAndEncodeAudioTask : public rtc::QueuedTask {
251 public:
252 ProcessAndEncodeAudioTask(std::unique_ptr<AudioFrame> audio_frame,
253 ChannelSend* channel)
254 : audio_frame_(std::move(audio_frame)), channel_(channel) {
255 RTC_DCHECK(channel_);
256 }
257
258 private:
259 bool Run() override {
260 RTC_DCHECK_RUN_ON(channel_->encoder_queue_);
261 channel_->ProcessAndEncodeAudioOnTaskQueue(audio_frame_.get());
262 return true;
263 }
264
265 std::unique_ptr<AudioFrame> audio_frame_;
266 ChannelSend* const channel_;
267};
268
269int32_t ChannelSend::SendData(FrameType frameType,
270 uint8_t payloadType,
271 uint32_t timeStamp,
272 const uint8_t* payloadData,
273 size_t payloadSize,
274 const RTPFragmentationHeader* fragmentation) {
275 RTC_DCHECK_RUN_ON(encoder_queue_);
Niels Möller7d76a312018-10-26 12:57:07 +0200276 rtc::ArrayView<const uint8_t> payload(payloadData, payloadSize);
277
278 if (media_transport() != nullptr) {
279 return SendMediaTransportAudio(frameType, payloadType, timeStamp, payload,
280 fragmentation);
281 } else {
282 return SendRtpAudio(frameType, payloadType, timeStamp, payload,
283 fragmentation);
284 }
285}
286
287int32_t ChannelSend::SendRtpAudio(FrameType frameType,
288 uint8_t payloadType,
289 uint32_t timeStamp,
290 rtc::ArrayView<const uint8_t> payload,
291 const RTPFragmentationHeader* fragmentation) {
292 RTC_DCHECK_RUN_ON(encoder_queue_);
Niels Möller530ead42018-10-04 14:28:39 +0200293 if (_includeAudioLevelIndication) {
294 // Store current audio level in the RTP/RTCP module.
295 // The level will be used in combination with voice-activity state
296 // (frameType) to add an RTP header extension
297 _rtpRtcpModule->SetAudioLevel(rms_level_.Average());
298 }
299
Benjamin Wright84583f62018-10-04 14:22:34 -0700300 // E2EE Custom Audio Frame Encryption (This is optional).
301 // Keep this buffer around for the lifetime of the send call.
302 rtc::Buffer encrypted_audio_payload;
303 if (frame_encryptor_ != nullptr) {
304 // TODO(benwright@webrtc.org) - Allocate enough to always encrypt inline.
305 // Allocate a buffer to hold the maximum possible encrypted payload.
306 size_t max_ciphertext_size = frame_encryptor_->GetMaxCiphertextByteSize(
Niels Möller7d76a312018-10-26 12:57:07 +0200307 cricket::MEDIA_TYPE_AUDIO, payload.size());
Benjamin Wright84583f62018-10-04 14:22:34 -0700308 encrypted_audio_payload.SetSize(max_ciphertext_size);
309
310 // Encrypt the audio payload into the buffer.
311 size_t bytes_written = 0;
312 int encrypt_status = frame_encryptor_->Encrypt(
313 cricket::MEDIA_TYPE_AUDIO, _rtpRtcpModule->SSRC(),
Niels Möller7d76a312018-10-26 12:57:07 +0200314 /*additional_data=*/nullptr, payload, encrypted_audio_payload,
315 &bytes_written);
Benjamin Wright84583f62018-10-04 14:22:34 -0700316 if (encrypt_status != 0) {
317 RTC_DLOG(LS_ERROR) << "Channel::SendData() failed encrypt audio payload: "
318 << encrypt_status;
319 return -1;
320 }
321 // Resize the buffer to the exact number of bytes actually used.
322 encrypted_audio_payload.SetSize(bytes_written);
323 // Rewrite the payloadData and size to the new encrypted payload.
Niels Möller7d76a312018-10-26 12:57:07 +0200324 payload = encrypted_audio_payload;
Benjamin Wrightbfb444c2018-10-15 10:20:24 -0700325 } else if (crypto_options_.sframe.require_frame_encryption) {
326 RTC_DLOG(LS_ERROR) << "Channel::SendData() failed sending audio payload: "
327 << "A frame encryptor is required but one is not set.";
328 return -1;
Benjamin Wright84583f62018-10-04 14:22:34 -0700329 }
330
Niels Möller530ead42018-10-04 14:28:39 +0200331 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
332 // packetization.
333 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
Niels Möller7d76a312018-10-26 12:57:07 +0200334 if (!_rtpRtcpModule->SendOutgoingData((FrameType&)frameType, payloadType,
335 timeStamp,
336 // Leaving the time when this frame was
337 // received from the capture device as
338 // undefined for voice for now.
339 -1, payload.data(), payload.size(),
340 fragmentation, nullptr, nullptr)) {
Niels Möller530ead42018-10-04 14:28:39 +0200341 RTC_DLOG(LS_ERROR)
342 << "ChannelSend::SendData() failed to send data to RTP/RTCP module";
343 return -1;
344 }
345
346 return 0;
347}
348
Niels Möller7d76a312018-10-26 12:57:07 +0200349int32_t ChannelSend::SendMediaTransportAudio(
350 FrameType frameType,
351 uint8_t payloadType,
352 uint32_t timeStamp,
353 rtc::ArrayView<const uint8_t> payload,
354 const RTPFragmentationHeader* fragmentation) {
355 RTC_DCHECK_RUN_ON(encoder_queue_);
356 // TODO(nisse): Use null _transportPtr for MediaTransport.
357 // RTC_DCHECK(_transportPtr == nullptr);
358 uint64_t channel_id;
359 int sampling_rate_hz;
360 {
361 rtc::CritScope cs(&media_transport_lock_);
362 if (media_transport_payload_type_ != payloadType) {
363 // Payload type is being changed, media_transport_sampling_frequency_,
364 // no longer current.
365 return -1;
366 }
367 sampling_rate_hz = media_transport_sampling_frequency_;
368 channel_id = media_transport_channel_id_;
369 }
370 const MediaTransportEncodedAudioFrame frame(
371 /*sampling_rate_hz=*/sampling_rate_hz,
372
373 // TODO(nisse): Timestamp and sample index are the same for all supported
374 // audio codecs except G722. Refactor audio coding module to only use
375 // sample index, and leave translation to RTP time, when needed, for
376 // RTP-specific code.
377 /*starting_sample_index=*/timeStamp,
378
379 // Sample count isn't conveniently available from the AudioCodingModule,
380 // and needs some refactoring to wire up in a good way. For now, left as
381 // zero.
382 /*sample_count=*/0,
383
384 /*sequence_number=*/media_transport_sequence_number_,
385 MediaTransportFrameTypeForWebrtcFrameType(frameType), payloadType,
386 std::vector<uint8_t>(payload.begin(), payload.end()));
387
388 // TODO(nisse): Introduce a MediaTransportSender object bound to a specific
389 // channel id.
390 RTCError rtc_error =
391 media_transport()->SendAudioFrame(channel_id, std::move(frame));
392
393 if (!rtc_error.ok()) {
394 RTC_LOG(LS_ERROR) << "Failed to send frame, rtc_error="
395 << ToString(rtc_error.type()) << ", "
396 << rtc_error.message();
397 return -1;
398 }
399
400 ++media_transport_sequence_number_;
401
402 return 0;
403}
404
Niels Möller530ead42018-10-04 14:28:39 +0200405bool ChannelSend::SendRtp(const uint8_t* data,
406 size_t len,
407 const PacketOptions& options) {
Niels Möller7d76a312018-10-26 12:57:07 +0200408 // We should not be sending RTP packets if media transport is available.
409 RTC_CHECK(!media_transport());
410
Niels Möller530ead42018-10-04 14:28:39 +0200411 rtc::CritScope cs(&_callbackCritSect);
412
413 if (_transportPtr == NULL) {
414 RTC_DLOG(LS_ERROR)
415 << "ChannelSend::SendPacket() failed to send RTP packet due to"
416 << " invalid transport object";
417 return false;
418 }
419
420 if (!_transportPtr->SendRtp(data, len, options)) {
421 RTC_DLOG(LS_ERROR) << "ChannelSend::SendPacket() RTP transmission failed";
422 return false;
423 }
424 return true;
425}
426
427bool ChannelSend::SendRtcp(const uint8_t* data, size_t len) {
428 rtc::CritScope cs(&_callbackCritSect);
429 if (_transportPtr == NULL) {
430 RTC_DLOG(LS_ERROR)
431 << "ChannelSend::SendRtcp() failed to send RTCP packet due to"
432 << " invalid transport object";
433 return false;
434 }
435
436 int n = _transportPtr->SendRtcp(data, len);
437 if (n < 0) {
438 RTC_DLOG(LS_ERROR) << "ChannelSend::SendRtcp() transmission failed";
439 return false;
440 }
441 return true;
442}
443
444int ChannelSend::PreferredSampleRate() const {
445 // Return the bigger of playout and receive frequency in the ACM.
446 return std::max(audio_coding_->ReceiveFrequency(),
447 audio_coding_->PlayoutFrequency());
448}
449
450ChannelSend::ChannelSend(rtc::TaskQueue* encoder_queue,
451 ProcessThread* module_process_thread,
Niels Möller7d76a312018-10-26 12:57:07 +0200452 MediaTransportInterface* media_transport,
Niels Möller530ead42018-10-04 14:28:39 +0200453 RtcpRttStats* rtcp_rtt_stats,
Benjamin Wright84583f62018-10-04 14:22:34 -0700454 RtcEventLog* rtc_event_log,
Benjamin Wrightbfb444c2018-10-15 10:20:24 -0700455 FrameEncryptorInterface* frame_encryptor,
Johannes Kron9190b822018-10-29 11:22:05 +0100456 const webrtc::CryptoOptions& crypto_options,
Jiawei Ou55718122018-11-09 13:17:39 -0800457 bool extmap_allow_mixed,
458 int rtcp_report_interval_ms)
Niels Möller530ead42018-10-04 14:28:39 +0200459 : event_log_(rtc_event_log),
460 _timeStamp(0), // This is just an offset, RTP module will add it's own
461 // random offset
462 send_sequence_number_(0),
463 _moduleProcessThreadPtr(module_process_thread),
464 _transportPtr(NULL),
465 input_mute_(false),
466 previous_frame_muted_(false),
467 _includeAudioLevelIndication(false),
468 transport_overhead_per_packet_(0),
469 rtp_overhead_per_packet_(0),
470 rtcp_observer_(new VoERtcpObserver(this)),
471 feedback_observer_proxy_(new TransportFeedbackProxy()),
472 seq_num_allocator_proxy_(new TransportSequenceNumberProxy()),
473 rtp_packet_sender_proxy_(new RtpPacketSenderProxy()),
474 retransmission_rate_limiter_(new RateLimiter(Clock::GetRealTimeClock(),
475 kMaxRetransmissionWindowMs)),
476 use_twcc_plr_for_ana_(
477 webrtc::field_trial::FindFullName("UseTwccPlrForAna") == "Enabled"),
Benjamin Wright84583f62018-10-04 14:22:34 -0700478 encoder_queue_(encoder_queue),
Niels Möller7d76a312018-10-26 12:57:07 +0200479 media_transport_(media_transport),
Benjamin Wrightbfb444c2018-10-15 10:20:24 -0700480 frame_encryptor_(frame_encryptor),
481 crypto_options_(crypto_options) {
Niels Möller530ead42018-10-04 14:28:39 +0200482 RTC_DCHECK(module_process_thread);
483 RTC_DCHECK(encoder_queue);
484 audio_coding_.reset(AudioCodingModule::Create(AudioCodingModule::Config()));
485
486 RtpRtcp::Configuration configuration;
487 configuration.audio = true;
488 configuration.outgoing_transport = this;
489 configuration.overhead_observer = this;
490 configuration.bandwidth_callback = rtcp_observer_.get();
491
492 configuration.paced_sender = rtp_packet_sender_proxy_.get();
493 configuration.transport_sequence_number_allocator =
494 seq_num_allocator_proxy_.get();
495 configuration.transport_feedback_callback = feedback_observer_proxy_.get();
496
497 configuration.event_log = event_log_;
498 configuration.rtt_stats = rtcp_rtt_stats;
499 configuration.retransmission_rate_limiter =
500 retransmission_rate_limiter_.get();
Johannes Kron9190b822018-10-29 11:22:05 +0100501 configuration.extmap_allow_mixed = extmap_allow_mixed;
Jiawei Ou55718122018-11-09 13:17:39 -0800502 configuration.rtcp_interval_config.audio_interval_ms =
503 rtcp_report_interval_ms;
Niels Möller530ead42018-10-04 14:28:39 +0200504
505 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
506 _rtpRtcpModule->SetSendingMediaStatus(false);
507 Init();
508}
509
510ChannelSend::~ChannelSend() {
511 Terminate();
512 RTC_DCHECK(!channel_state_.Get().sending);
513}
514
515void ChannelSend::Init() {
516 channel_state_.Reset();
517
518 // --- Add modules to process thread (for periodic schedulation)
519 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get(), RTC_FROM_HERE);
520
521 // --- ACM initialization
522 int error = audio_coding_->InitializeReceiver();
523 RTC_DCHECK_EQ(0, error);
524
525 // --- RTP/RTCP module initialization
526
527 // Ensure that RTCP is enabled by default for the created channel.
528 // Note that, the module will keep generating RTCP until it is explicitly
529 // disabled by the user.
530 // After StopListen (when no sockets exists), RTCP packets will no longer
531 // be transmitted since the Transport object will then be invalid.
532 // RTCP is enabled by default.
533 _rtpRtcpModule->SetRTCPStatus(RtcpMode::kCompound);
534
535 // --- Register all permanent callbacks
536 error = audio_coding_->RegisterTransportCallback(this);
537 RTC_DCHECK_EQ(0, error);
538}
539
540void ChannelSend::Terminate() {
541 RTC_DCHECK(construction_thread_.CalledOnValidThread());
542 // Must be called on the same thread as Init().
543
544 StopSend();
545
546 // The order to safely shutdown modules in a channel is:
547 // 1. De-register callbacks in modules
548 // 2. De-register modules in process thread
549 // 3. Destroy modules
550 int error = audio_coding_->RegisterTransportCallback(NULL);
551 RTC_DCHECK_EQ(0, error);
552
553 // De-register modules in process thread
554 if (_moduleProcessThreadPtr)
555 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
556
557 // End of modules shutdown
558}
559
560int32_t ChannelSend::StartSend() {
561 if (channel_state_.Get().sending) {
562 return 0;
563 }
564 channel_state_.SetSending(true);
565
566 // Resume the previous sequence number which was reset by StopSend(). This
567 // needs to be done before |sending| is set to true on the RTP/RTCP module.
568 if (send_sequence_number_) {
569 _rtpRtcpModule->SetSequenceNumber(send_sequence_number_);
570 }
571 _rtpRtcpModule->SetSendingMediaStatus(true);
572 if (_rtpRtcpModule->SetSendingStatus(true) != 0) {
573 RTC_DLOG(LS_ERROR) << "StartSend() RTP/RTCP failed to start sending";
574 _rtpRtcpModule->SetSendingMediaStatus(false);
575 rtc::CritScope cs(&_callbackCritSect);
576 channel_state_.SetSending(false);
577 return -1;
578 }
579 {
580 // It is now OK to start posting tasks to the encoder task queue.
581 rtc::CritScope cs(&encoder_queue_lock_);
582 encoder_queue_is_active_ = true;
583 }
584 return 0;
585}
586
587void ChannelSend::StopSend() {
588 if (!channel_state_.Get().sending) {
589 return;
590 }
591 channel_state_.SetSending(false);
592
593 // Post a task to the encoder thread which sets an event when the task is
594 // executed. We know that no more encoding tasks will be added to the task
595 // queue for this channel since sending is now deactivated. It means that,
596 // if we wait for the event to bet set, we know that no more pending tasks
597 // exists and it is therfore guaranteed that the task queue will never try
598 // to acccess and invalid channel object.
599 RTC_DCHECK(encoder_queue_);
600
Niels Möllerc572ff32018-11-07 08:43:50 +0100601 rtc::Event flush;
Niels Möller530ead42018-10-04 14:28:39 +0200602 {
603 // Clear |encoder_queue_is_active_| under lock to prevent any other tasks
604 // than this final "flush task" to be posted on the queue.
605 rtc::CritScope cs(&encoder_queue_lock_);
606 encoder_queue_is_active_ = false;
607 encoder_queue_->PostTask([&flush]() { flush.Set(); });
608 }
609 flush.Wait(rtc::Event::kForever);
610
611 // Store the sequence number to be able to pick up the same sequence for
612 // the next StartSend(). This is needed for restarting device, otherwise
613 // it might cause libSRTP to complain about packets being replayed.
614 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
615 // CL is landed. See issue
616 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
617 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
618
619 // Reset sending SSRC and sequence number and triggers direct transmission
620 // of RTCP BYE
621 if (_rtpRtcpModule->SetSendingStatus(false) == -1) {
622 RTC_DLOG(LS_ERROR) << "StartSend() RTP/RTCP failed to stop sending";
623 }
624 _rtpRtcpModule->SetSendingMediaStatus(false);
625}
626
627bool ChannelSend::SetEncoder(int payload_type,
628 std::unique_ptr<AudioEncoder> encoder) {
629 RTC_DCHECK_GE(payload_type, 0);
630 RTC_DCHECK_LE(payload_type, 127);
631 // TODO(ossu): Make CodecInsts up, for now: one for the RTP/RTCP module and
632 // one for for us to keep track of sample rate and number of channels, etc.
633
634 // The RTP/RTCP module needs to know the RTP timestamp rate (i.e. clockrate)
635 // as well as some other things, so we collect this info and send it along.
636 CodecInst rtp_codec;
637 rtp_codec.pltype = payload_type;
638 strncpy(rtp_codec.plname, "audio", sizeof(rtp_codec.plname));
639 rtp_codec.plname[sizeof(rtp_codec.plname) - 1] = 0;
640 // Seems unclear if it should be clock rate or sample rate. CodecInst
641 // supposedly carries the sample rate, but only clock rate seems sensible to
642 // send to the RTP/RTCP module.
643 rtp_codec.plfreq = encoder->RtpTimestampRateHz();
644 rtp_codec.pacsize = rtc::CheckedDivExact(
645 static_cast<int>(encoder->Max10MsFramesInAPacket() * rtp_codec.plfreq),
646 100);
647 rtp_codec.channels = encoder->NumChannels();
648 rtp_codec.rate = 0;
649
650 if (_rtpRtcpModule->RegisterSendPayload(rtp_codec) != 0) {
651 _rtpRtcpModule->DeRegisterSendPayload(payload_type);
652 if (_rtpRtcpModule->RegisterSendPayload(rtp_codec) != 0) {
653 RTC_DLOG(LS_ERROR)
654 << "SetEncoder() failed to register codec to RTP/RTCP module";
655 return false;
656 }
657 }
658
Niels Möller7d76a312018-10-26 12:57:07 +0200659 if (media_transport_) {
660 rtc::CritScope cs(&media_transport_lock_);
661 media_transport_payload_type_ = payload_type;
662 // TODO(nisse): Currently broken for G722, since timestamps passed through
663 // encoder use RTP clock rather than sample count, and they differ for G722.
664 media_transport_sampling_frequency_ = encoder->RtpTimestampRateHz();
665 }
Niels Möller530ead42018-10-04 14:28:39 +0200666 audio_coding_->SetEncoder(std::move(encoder));
667 return true;
668}
669
670void ChannelSend::ModifyEncoder(
671 rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier) {
672 audio_coding_->ModifyEncoder(modifier);
673}
674
675void ChannelSend::SetBitRate(int bitrate_bps, int64_t probing_interval_ms) {
676 audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
677 if (*encoder) {
678 (*encoder)->OnReceivedUplinkBandwidth(bitrate_bps, probing_interval_ms);
679 }
680 });
681 retransmission_rate_limiter_->SetMaxRate(bitrate_bps);
Sebastian Jansson359d60a2018-10-25 16:22:02 +0200682 configured_bitrate_bps_ = bitrate_bps;
683}
684
685int ChannelSend::GetBitRate() const {
686 return configured_bitrate_bps_;
Niels Möller530ead42018-10-04 14:28:39 +0200687}
688
689void ChannelSend::OnTwccBasedUplinkPacketLossRate(float packet_loss_rate) {
690 if (!use_twcc_plr_for_ana_)
691 return;
692 audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
693 if (*encoder) {
694 (*encoder)->OnReceivedUplinkPacketLossFraction(packet_loss_rate);
695 }
696 });
697}
698
699void ChannelSend::OnRecoverableUplinkPacketLossRate(
700 float recoverable_packet_loss_rate) {
701 audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
702 if (*encoder) {
703 (*encoder)->OnReceivedUplinkRecoverablePacketLossFraction(
704 recoverable_packet_loss_rate);
705 }
706 });
707}
708
709void ChannelSend::OnUplinkPacketLossRate(float packet_loss_rate) {
710 if (use_twcc_plr_for_ana_)
711 return;
712 audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
713 if (*encoder) {
714 (*encoder)->OnReceivedUplinkPacketLossFraction(packet_loss_rate);
715 }
716 });
717}
718
719bool ChannelSend::EnableAudioNetworkAdaptor(const std::string& config_string) {
720 bool success = false;
721 audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
722 if (*encoder) {
723 success =
724 (*encoder)->EnableAudioNetworkAdaptor(config_string, event_log_);
725 }
726 });
727 return success;
728}
729
730void ChannelSend::DisableAudioNetworkAdaptor() {
731 audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
732 if (*encoder)
733 (*encoder)->DisableAudioNetworkAdaptor();
734 });
735}
736
737void ChannelSend::SetReceiverFrameLengthRange(int min_frame_length_ms,
738 int max_frame_length_ms) {
739 audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
740 if (*encoder) {
741 (*encoder)->SetReceiverFrameLengthRange(min_frame_length_ms,
742 max_frame_length_ms);
743 }
744 });
745}
746
747void ChannelSend::RegisterTransport(Transport* transport) {
748 rtc::CritScope cs(&_callbackCritSect);
749 _transportPtr = transport;
750}
751
752int32_t ChannelSend::ReceivedRTCPPacket(const uint8_t* data, size_t length) {
753 // Deliver RTCP packet to RTP/RTCP module for parsing
754 _rtpRtcpModule->IncomingRtcpPacket(data, length);
755
756 int64_t rtt = GetRTT();
757 if (rtt == 0) {
758 // Waiting for valid RTT.
759 return 0;
760 }
761
762 int64_t nack_window_ms = rtt;
763 if (nack_window_ms < kMinRetransmissionWindowMs) {
764 nack_window_ms = kMinRetransmissionWindowMs;
765 } else if (nack_window_ms > kMaxRetransmissionWindowMs) {
766 nack_window_ms = kMaxRetransmissionWindowMs;
767 }
768 retransmission_rate_limiter_->SetWindowSize(nack_window_ms);
769
770 // Invoke audio encoders OnReceivedRtt().
771 audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
772 if (*encoder)
773 (*encoder)->OnReceivedRtt(rtt);
774 });
775
776 return 0;
777}
778
779void ChannelSend::SetInputMute(bool enable) {
780 rtc::CritScope cs(&volume_settings_critsect_);
781 input_mute_ = enable;
782}
783
784bool ChannelSend::InputMute() const {
785 rtc::CritScope cs(&volume_settings_critsect_);
786 return input_mute_;
787}
788
789int ChannelSend::SendTelephoneEventOutband(int event, int duration_ms) {
790 RTC_DCHECK_LE(0, event);
791 RTC_DCHECK_GE(255, event);
792 RTC_DCHECK_LE(0, duration_ms);
793 RTC_DCHECK_GE(65535, duration_ms);
794 if (!Sending()) {
795 return -1;
796 }
797 if (_rtpRtcpModule->SendTelephoneEventOutband(
798 event, duration_ms, kTelephoneEventAttenuationdB) != 0) {
799 RTC_DLOG(LS_ERROR) << "SendTelephoneEventOutband() failed to send event";
800 return -1;
801 }
802 return 0;
803}
804
805int ChannelSend::SetSendTelephoneEventPayloadType(int payload_type,
806 int payload_frequency) {
807 RTC_DCHECK_LE(0, payload_type);
808 RTC_DCHECK_GE(127, payload_type);
809 CodecInst codec = {0};
810 codec.pltype = payload_type;
811 codec.plfreq = payload_frequency;
812 memcpy(codec.plname, "telephone-event", 16);
813 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
814 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
815 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
816 RTC_DLOG(LS_ERROR)
817 << "SetSendTelephoneEventPayloadType() failed to register "
818 "send payload type";
819 return -1;
820 }
821 }
822 return 0;
823}
824
825int ChannelSend::SetLocalSSRC(unsigned int ssrc) {
826 if (channel_state_.Get().sending) {
827 RTC_DLOG(LS_ERROR) << "SetLocalSSRC() already sending";
828 return -1;
829 }
Niels Möller7d76a312018-10-26 12:57:07 +0200830 if (media_transport_) {
831 rtc::CritScope cs(&media_transport_lock_);
832 media_transport_channel_id_ = ssrc;
833 }
Niels Möller530ead42018-10-04 14:28:39 +0200834 _rtpRtcpModule->SetSSRC(ssrc);
835 return 0;
836}
837
838void ChannelSend::SetMid(const std::string& mid, int extension_id) {
839 int ret = SetSendRtpHeaderExtension(true, kRtpExtensionMid, extension_id);
840 RTC_DCHECK_EQ(0, ret);
841 _rtpRtcpModule->SetMid(mid);
842}
843
Johannes Kron9190b822018-10-29 11:22:05 +0100844void ChannelSend::SetExtmapAllowMixed(bool extmap_allow_mixed) {
845 _rtpRtcpModule->SetExtmapAllowMixed(extmap_allow_mixed);
846}
847
Niels Möller530ead42018-10-04 14:28:39 +0200848int ChannelSend::SetSendAudioLevelIndicationStatus(bool enable,
849 unsigned char id) {
850 _includeAudioLevelIndication = enable;
851 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
852}
853
854void ChannelSend::EnableSendTransportSequenceNumber(int id) {
855 int ret =
856 SetSendRtpHeaderExtension(true, kRtpExtensionTransportSequenceNumber, id);
857 RTC_DCHECK_EQ(0, ret);
858}
859
860void ChannelSend::RegisterSenderCongestionControlObjects(
861 RtpTransportControllerSendInterface* transport,
862 RtcpBandwidthObserver* bandwidth_observer) {
863 RtpPacketSender* rtp_packet_sender = transport->packet_sender();
864 TransportFeedbackObserver* transport_feedback_observer =
865 transport->transport_feedback_observer();
866 PacketRouter* packet_router = transport->packet_router();
867
868 RTC_DCHECK(rtp_packet_sender);
869 RTC_DCHECK(transport_feedback_observer);
870 RTC_DCHECK(packet_router);
871 RTC_DCHECK(!packet_router_);
872 rtcp_observer_->SetBandwidthObserver(bandwidth_observer);
873 feedback_observer_proxy_->SetTransportFeedbackObserver(
874 transport_feedback_observer);
875 seq_num_allocator_proxy_->SetSequenceNumberAllocator(packet_router);
876 rtp_packet_sender_proxy_->SetPacketSender(rtp_packet_sender);
877 _rtpRtcpModule->SetStorePacketsStatus(true, 600);
878 constexpr bool remb_candidate = false;
879 packet_router->AddSendRtpModule(_rtpRtcpModule.get(), remb_candidate);
880 packet_router_ = packet_router;
881}
882
883void ChannelSend::ResetSenderCongestionControlObjects() {
884 RTC_DCHECK(packet_router_);
885 _rtpRtcpModule->SetStorePacketsStatus(false, 600);
886 rtcp_observer_->SetBandwidthObserver(nullptr);
887 feedback_observer_proxy_->SetTransportFeedbackObserver(nullptr);
888 seq_num_allocator_proxy_->SetSequenceNumberAllocator(nullptr);
889 packet_router_->RemoveSendRtpModule(_rtpRtcpModule.get());
890 packet_router_ = nullptr;
891 rtp_packet_sender_proxy_->SetPacketSender(nullptr);
892}
893
894void ChannelSend::SetRTCPStatus(bool enable) {
895 _rtpRtcpModule->SetRTCPStatus(enable ? RtcpMode::kCompound : RtcpMode::kOff);
896}
897
898int ChannelSend::SetRTCP_CNAME(const char cName[256]) {
899 if (_rtpRtcpModule->SetCNAME(cName) != 0) {
900 RTC_DLOG(LS_ERROR) << "SetRTCP_CNAME() failed to set RTCP CNAME";
901 return -1;
902 }
903 return 0;
904}
905
906int ChannelSend::GetRemoteRTCPReportBlocks(
907 std::vector<ReportBlock>* report_blocks) {
908 if (report_blocks == NULL) {
909 RTC_DLOG(LS_ERROR) << "GetRemoteRTCPReportBlock()s invalid report_blocks.";
910 return -1;
911 }
912
913 // Get the report blocks from the latest received RTCP Sender or Receiver
914 // Report. Each element in the vector contains the sender's SSRC and a
915 // report block according to RFC 3550.
916 std::vector<RTCPReportBlock> rtcp_report_blocks;
917 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
918 return -1;
919 }
920
921 if (rtcp_report_blocks.empty())
922 return 0;
923
924 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
925 for (; it != rtcp_report_blocks.end(); ++it) {
926 ReportBlock report_block;
927 report_block.sender_SSRC = it->sender_ssrc;
928 report_block.source_SSRC = it->source_ssrc;
929 report_block.fraction_lost = it->fraction_lost;
930 report_block.cumulative_num_packets_lost = it->packets_lost;
931 report_block.extended_highest_sequence_number =
932 it->extended_highest_sequence_number;
933 report_block.interarrival_jitter = it->jitter;
934 report_block.last_SR_timestamp = it->last_sender_report_timestamp;
935 report_block.delay_since_last_SR = it->delay_since_last_sender_report;
936 report_blocks->push_back(report_block);
937 }
938 return 0;
939}
940
941int ChannelSend::GetRTPStatistics(CallSendStatistics& stats) {
942 // --- RtcpStatistics
943
944 // --- RTT
945 stats.rttMs = GetRTT();
946
947 // --- Data counters
948
949 size_t bytesSent(0);
950 uint32_t packetsSent(0);
951
952 if (_rtpRtcpModule->DataCountersRTP(&bytesSent, &packetsSent) != 0) {
953 RTC_DLOG(LS_WARNING)
954 << "GetRTPStatistics() failed to retrieve RTP datacounters"
955 << " => output will not be complete";
956 }
957
958 stats.bytesSent = bytesSent;
959 stats.packetsSent = packetsSent;
960
961 return 0;
962}
963
964void ChannelSend::SetNACKStatus(bool enable, int maxNumberOfPackets) {
965 // None of these functions can fail.
966 if (enable)
967 audio_coding_->EnableNack(maxNumberOfPackets);
968 else
969 audio_coding_->DisableNack();
970}
971
972// Called when we are missing one or more packets.
973int ChannelSend::ResendPackets(const uint16_t* sequence_numbers, int length) {
974 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
975}
976
977void ChannelSend::ProcessAndEncodeAudio(
978 std::unique_ptr<AudioFrame> audio_frame) {
979 // Avoid posting any new tasks if sending was already stopped in StopSend().
980 rtc::CritScope cs(&encoder_queue_lock_);
981 if (!encoder_queue_is_active_) {
982 return;
983 }
984 // Profile time between when the audio frame is added to the task queue and
985 // when the task is actually executed.
986 audio_frame->UpdateProfileTimeStamp();
987 encoder_queue_->PostTask(std::unique_ptr<rtc::QueuedTask>(
988 new ProcessAndEncodeAudioTask(std::move(audio_frame), this)));
989}
990
991void ChannelSend::ProcessAndEncodeAudioOnTaskQueue(AudioFrame* audio_input) {
992 RTC_DCHECK_RUN_ON(encoder_queue_);
993 RTC_DCHECK_GT(audio_input->samples_per_channel_, 0);
994 RTC_DCHECK_LE(audio_input->num_channels_, 2);
995
996 // Measure time between when the audio frame is added to the task queue and
997 // when the task is actually executed. Goal is to keep track of unwanted
998 // extra latency added by the task queue.
999 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Audio.EncodingTaskQueueLatencyMs",
1000 audio_input->ElapsedProfileTimeMs());
1001
1002 bool is_muted = InputMute();
1003 AudioFrameOperations::Mute(audio_input, previous_frame_muted_, is_muted);
1004
1005 if (_includeAudioLevelIndication) {
1006 size_t length =
1007 audio_input->samples_per_channel_ * audio_input->num_channels_;
1008 RTC_CHECK_LE(length, AudioFrame::kMaxDataSizeBytes);
1009 if (is_muted && previous_frame_muted_) {
1010 rms_level_.AnalyzeMuted(length);
1011 } else {
1012 rms_level_.Analyze(
1013 rtc::ArrayView<const int16_t>(audio_input->data(), length));
1014 }
1015 }
1016 previous_frame_muted_ = is_muted;
1017
1018 // Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
1019
1020 // The ACM resamples internally.
1021 audio_input->timestamp_ = _timeStamp;
1022 // This call will trigger AudioPacketizationCallback::SendData if encoding
1023 // is done and payload is ready for packetization and transmission.
1024 // Otherwise, it will return without invoking the callback.
1025 if (audio_coding_->Add10MsData(*audio_input) < 0) {
1026 RTC_DLOG(LS_ERROR) << "ACM::Add10MsData() failed.";
1027 return;
1028 }
1029
1030 _timeStamp += static_cast<uint32_t>(audio_input->samples_per_channel_);
1031}
1032
1033void ChannelSend::UpdateOverheadForEncoder() {
1034 size_t overhead_per_packet =
1035 transport_overhead_per_packet_ + rtp_overhead_per_packet_;
1036 audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
1037 if (*encoder) {
1038 (*encoder)->OnReceivedOverhead(overhead_per_packet);
1039 }
1040 });
1041}
1042
1043void ChannelSend::SetTransportOverhead(size_t transport_overhead_per_packet) {
1044 rtc::CritScope cs(&overhead_per_packet_lock_);
1045 transport_overhead_per_packet_ = transport_overhead_per_packet;
1046 UpdateOverheadForEncoder();
1047}
1048
1049// TODO(solenberg): Make AudioSendStream an OverheadObserver instead.
1050void ChannelSend::OnOverheadChanged(size_t overhead_bytes_per_packet) {
1051 rtc::CritScope cs(&overhead_per_packet_lock_);
1052 rtp_overhead_per_packet_ = overhead_bytes_per_packet;
1053 UpdateOverheadForEncoder();
1054}
1055
1056ANAStats ChannelSend::GetANAStatistics() const {
1057 return audio_coding_->GetANAStats();
1058}
1059
1060RtpRtcp* ChannelSend::GetRtpRtcp() const {
1061 return _rtpRtcpModule.get();
1062}
1063
1064int ChannelSend::SetSendRtpHeaderExtension(bool enable,
1065 RTPExtensionType type,
1066 unsigned char id) {
1067 int error = 0;
1068 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
1069 if (enable) {
1070 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
1071 }
1072 return error;
1073}
1074
1075int ChannelSend::GetRtpTimestampRateHz() const {
1076 const auto format = audio_coding_->ReceiveFormat();
1077 // Default to the playout frequency if we've not gotten any packets yet.
1078 // TODO(ossu): Zero clockrate can only happen if we've added an external
1079 // decoder for a format we don't support internally. Remove once that way of
1080 // adding decoders is gone!
1081 return (format && format->clockrate_hz != 0)
1082 ? format->clockrate_hz
1083 : audio_coding_->PlayoutFrequency();
1084}
1085
1086int64_t ChannelSend::GetRTT() const {
1087 RtcpMode method = _rtpRtcpModule->RTCP();
1088 if (method == RtcpMode::kOff) {
1089 return 0;
1090 }
1091 std::vector<RTCPReportBlock> report_blocks;
1092 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
1093
1094 if (report_blocks.empty()) {
1095 return 0;
1096 }
1097
1098 int64_t rtt = 0;
1099 int64_t avg_rtt = 0;
1100 int64_t max_rtt = 0;
1101 int64_t min_rtt = 0;
1102 // We don't know in advance the remote ssrc used by the other end's receiver
1103 // reports, so use the SSRC of the first report block for calculating the RTT.
1104 if (_rtpRtcpModule->RTT(report_blocks[0].sender_ssrc, &rtt, &avg_rtt,
1105 &min_rtt, &max_rtt) != 0) {
1106 return 0;
1107 }
1108 return rtt;
1109}
1110
Benjamin Wright78410ad2018-10-25 09:52:57 -07001111void ChannelSend::SetFrameEncryptor(
1112 rtc::scoped_refptr<FrameEncryptorInterface> frame_encryptor) {
Benjamin Wright84583f62018-10-04 14:22:34 -07001113 rtc::CritScope cs(&encoder_queue_lock_);
1114 if (encoder_queue_is_active_) {
1115 encoder_queue_->PostTask([this, frame_encryptor]() {
Benjamin Wright78410ad2018-10-25 09:52:57 -07001116 this->frame_encryptor_ = std::move(frame_encryptor);
Benjamin Wright84583f62018-10-04 14:22:34 -07001117 });
1118 } else {
Benjamin Wright78410ad2018-10-25 09:52:57 -07001119 frame_encryptor_ = std::move(frame_encryptor);
Benjamin Wright84583f62018-10-04 14:22:34 -07001120 }
1121}
1122
Niels Möller530ead42018-10-04 14:28:39 +02001123} // namespace voe
1124} // namespace webrtc