OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 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/modules/audio_coding/main/acm2/acm_receiver.h" | 11 #include "webrtc/modules/audio_coding/main/acm2/acm_receiver.h" |
12 | 12 |
13 #include <stdlib.h> // malloc | 13 #include <stdlib.h> // malloc |
14 | 14 |
15 #include <algorithm> // sort | 15 #include <algorithm> // sort |
16 #include <vector> | 16 #include <vector> |
17 | 17 |
18 #include "webrtc/base/checks.h" | 18 #include "webrtc/base/checks.h" |
19 #include "webrtc/base/format_macros.h" | 19 #include "webrtc/base/format_macros.h" |
20 #include "webrtc/base/logging.h" | 20 #include "webrtc/base/logging.h" |
21 #include "webrtc/common_audio/signal_processing/include/signal_processing_librar
y.h" | 21 #include "webrtc/common_audio/signal_processing/include/signal_processing_librar
y.h" |
22 #include "webrtc/common_types.h" | 22 #include "webrtc/common_types.h" |
23 #include "webrtc/modules/audio_coding/codecs/audio_decoder.h" | 23 #include "webrtc/modules/audio_coding/codecs/audio_decoder.h" |
24 #include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h" | |
25 #include "webrtc/modules/audio_coding/main/acm2/acm_resampler.h" | 24 #include "webrtc/modules/audio_coding/main/acm2/acm_resampler.h" |
26 #include "webrtc/modules/audio_coding/main/acm2/call_statistics.h" | 25 #include "webrtc/modules/audio_coding/main/acm2/call_statistics.h" |
27 #include "webrtc/modules/audio_coding/neteq/include/neteq.h" | 26 #include "webrtc/modules/audio_coding/neteq/include/neteq.h" |
28 #include "webrtc/system_wrappers/include/clock.h" | 27 #include "webrtc/system_wrappers/include/clock.h" |
29 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | 28 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" |
30 #include "webrtc/system_wrappers/include/tick_util.h" | 29 #include "webrtc/system_wrappers/include/tick_util.h" |
31 #include "webrtc/system_wrappers/include/trace.h" | 30 #include "webrtc/system_wrappers/include/trace.h" |
32 | 31 |
33 namespace webrtc { | 32 namespace webrtc { |
34 | 33 |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), | 122 : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), |
124 id_(config.id), | 123 id_(config.id), |
125 last_audio_decoder_(nullptr), | 124 last_audio_decoder_(nullptr), |
126 previous_audio_activity_(AudioFrame::kVadPassive), | 125 previous_audio_activity_(AudioFrame::kVadPassive), |
127 current_sample_rate_hz_(config.neteq_config.sample_rate_hz), | 126 current_sample_rate_hz_(config.neteq_config.sample_rate_hz), |
128 audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]), | 127 audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]), |
129 last_audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]), | 128 last_audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]), |
130 neteq_(NetEq::Create(config.neteq_config)), | 129 neteq_(NetEq::Create(config.neteq_config)), |
131 vad_enabled_(config.neteq_config.enable_post_decode_vad), | 130 vad_enabled_(config.neteq_config.enable_post_decode_vad), |
132 clock_(config.clock), | 131 clock_(config.clock), |
133 resampled_last_output_frame_(true), | 132 resampled_last_output_frame_(true) { |
134 av_sync_(false), | |
135 initial_delay_manager_(), | |
136 missing_packets_sync_stream_(), | |
137 late_packets_sync_stream_() { | |
138 assert(clock_); | 133 assert(clock_); |
139 memset(audio_buffer_.get(), 0, AudioFrame::kMaxDataSizeSamples); | 134 memset(audio_buffer_.get(), 0, AudioFrame::kMaxDataSizeSamples); |
140 memset(last_audio_buffer_.get(), 0, AudioFrame::kMaxDataSizeSamples); | 135 memset(last_audio_buffer_.get(), 0, AudioFrame::kMaxDataSizeSamples); |
141 } | 136 } |
142 | 137 |
143 AcmReceiver::~AcmReceiver() { | 138 AcmReceiver::~AcmReceiver() { |
144 delete neteq_; | 139 delete neteq_; |
145 } | 140 } |
146 | 141 |
147 int AcmReceiver::SetMinimumDelay(int delay_ms) { | 142 int AcmReceiver::SetMinimumDelay(int delay_ms) { |
148 if (neteq_->SetMinimumDelay(delay_ms)) | 143 if (neteq_->SetMinimumDelay(delay_ms)) |
149 return 0; | 144 return 0; |
150 LOG(LERROR) << "AcmReceiver::SetExtraDelay " << delay_ms; | 145 LOG(LERROR) << "AcmReceiver::SetExtraDelay " << delay_ms; |
151 return -1; | 146 return -1; |
152 } | 147 } |
153 | 148 |
154 int AcmReceiver::SetInitialDelay(int delay_ms) { | |
155 if (delay_ms < 0 || delay_ms > 10000) { | |
156 return -1; | |
157 } | |
158 CriticalSectionScoped lock(crit_sect_.get()); | |
159 | |
160 if (delay_ms == 0) { | |
161 av_sync_ = false; | |
162 initial_delay_manager_.reset(); | |
163 missing_packets_sync_stream_.reset(); | |
164 late_packets_sync_stream_.reset(); | |
165 neteq_->SetMinimumDelay(0); | |
166 return 0; | |
167 } | |
168 | |
169 if (av_sync_ && initial_delay_manager_->PacketBuffered()) { | |
170 // Too late for this API. Only works before a call is started. | |
171 return -1; | |
172 } | |
173 | |
174 // Most of places NetEq calls are not within AcmReceiver's critical section to | |
175 // improve performance. Here, this call has to be placed before the following | |
176 // block, therefore, we keep it inside critical section. Otherwise, we have to | |
177 // release |neteq_crit_sect_| and acquire it again, which seems an overkill. | |
178 if (!neteq_->SetMinimumDelay(delay_ms)) | |
179 return -1; | |
180 | |
181 const int kLatePacketThreshold = 5; | |
182 av_sync_ = true; | |
183 initial_delay_manager_.reset(new InitialDelayManager(delay_ms, | |
184 kLatePacketThreshold)); | |
185 missing_packets_sync_stream_.reset(new InitialDelayManager::SyncStream); | |
186 late_packets_sync_stream_.reset(new InitialDelayManager::SyncStream); | |
187 return 0; | |
188 } | |
189 | |
190 int AcmReceiver::SetMaximumDelay(int delay_ms) { | 149 int AcmReceiver::SetMaximumDelay(int delay_ms) { |
191 if (neteq_->SetMaximumDelay(delay_ms)) | 150 if (neteq_->SetMaximumDelay(delay_ms)) |
192 return 0; | 151 return 0; |
193 LOG(LERROR) << "AcmReceiver::SetExtraDelay " << delay_ms; | 152 LOG(LERROR) << "AcmReceiver::SetExtraDelay " << delay_ms; |
194 return -1; | 153 return -1; |
195 } | 154 } |
196 | 155 |
197 int AcmReceiver::LeastRequiredDelayMs() const { | 156 int AcmReceiver::LeastRequiredDelayMs() const { |
198 return neteq_->LeastRequiredDelayMs(); | 157 return neteq_->LeastRequiredDelayMs(); |
199 } | 158 } |
200 | 159 |
201 int AcmReceiver::current_sample_rate_hz() const { | 160 int AcmReceiver::current_sample_rate_hz() const { |
202 CriticalSectionScoped lock(crit_sect_.get()); | 161 CriticalSectionScoped lock(crit_sect_.get()); |
203 return current_sample_rate_hz_; | 162 return current_sample_rate_hz_; |
204 } | 163 } |
205 | 164 |
206 int AcmReceiver::InsertPacket(const WebRtcRTPHeader& rtp_header, | 165 int AcmReceiver::InsertPacket(const WebRtcRTPHeader& rtp_header, |
207 const uint8_t* incoming_payload, | 166 const uint8_t* incoming_payload, |
208 size_t length_payload) { | 167 size_t length_payload) { |
209 uint32_t receive_timestamp = 0; | 168 uint32_t receive_timestamp = 0; |
210 InitialDelayManager::PacketType packet_type = | |
211 InitialDelayManager::kUndefinedPacket; | |
212 bool new_codec = false; | |
213 const RTPHeader* header = &rtp_header.header; // Just a shorthand. | 169 const RTPHeader* header = &rtp_header.header; // Just a shorthand. |
214 | 170 |
215 { | 171 { |
216 CriticalSectionScoped lock(crit_sect_.get()); | 172 CriticalSectionScoped lock(crit_sect_.get()); |
217 | 173 |
218 const Decoder* decoder = RtpHeaderToDecoder(*header, incoming_payload); | 174 const Decoder* decoder = RtpHeaderToDecoder(*header, incoming_payload); |
219 if (!decoder) { | 175 if (!decoder) { |
220 LOG_F(LS_ERROR) << "Payload-type " | 176 LOG_F(LS_ERROR) << "Payload-type " |
221 << static_cast<int>(header->payloadType) | 177 << static_cast<int>(header->payloadType) |
222 << " is not registered."; | 178 << " is not registered."; |
223 return -1; | 179 return -1; |
224 } | 180 } |
225 const int sample_rate_hz = ACMCodecDB::CodecFreq(decoder->acm_codec_id); | 181 const int sample_rate_hz = ACMCodecDB::CodecFreq(decoder->acm_codec_id); |
226 receive_timestamp = NowInTimestamp(sample_rate_hz); | 182 receive_timestamp = NowInTimestamp(sample_rate_hz); |
227 | 183 |
228 if (IsCng(decoder->acm_codec_id)) { | 184 // If this is a CNG while the audio codec is not mono, skip pushing in |
229 // If this is a CNG while the audio codec is not mono skip pushing in | 185 // packets into NetEq. |
230 // packets into NetEq. | 186 if (IsCng(decoder->acm_codec_id) && last_audio_decoder_ && |
231 if (last_audio_decoder_ && last_audio_decoder_->channels > 1) | 187 last_audio_decoder_->channels > 1) |
232 return 0; | 188 return 0; |
233 packet_type = InitialDelayManager::kCngPacket; | 189 if (!IsCng(decoder->acm_codec_id) && |
234 } else if (decoder->acm_codec_id == | 190 decoder->acm_codec_id != |
235 *RentACodec::CodecIndexFromId(RentACodec::CodecId::kAVT)) { | 191 *RentACodec::CodecIndexFromId(RentACodec::CodecId::kAVT)) { |
236 packet_type = InitialDelayManager::kAvtPacket; | 192 last_audio_decoder_ = decoder; |
237 } else { | |
238 if (decoder != last_audio_decoder_) { | |
239 // This is either the first audio packet or send codec is changed. | |
240 // Therefore, either NetEq buffer is empty or will be flushed when this | |
241 // packet is inserted. | |
242 new_codec = true; | |
243 last_audio_decoder_ = decoder; | |
244 } | |
245 packet_type = InitialDelayManager::kAudioPacket; | |
246 } | 193 } |
247 | 194 |
248 if (av_sync_) { | |
249 assert(initial_delay_manager_.get()); | |
250 assert(missing_packets_sync_stream_.get()); | |
251 // This updates |initial_delay_manager_| and specifies an stream of | |
252 // sync-packets, if required to be inserted. We insert the sync-packets | |
253 // when AcmReceiver lock is released and |decoder_lock_| is acquired. | |
254 initial_delay_manager_->UpdateLastReceivedPacket( | |
255 rtp_header, receive_timestamp, packet_type, new_codec, sample_rate_hz, | |
256 missing_packets_sync_stream_.get()); | |
257 } | |
258 } // |crit_sect_| is released. | 195 } // |crit_sect_| is released. |
259 | 196 |
260 // If |missing_packets_sync_stream_| is allocated then we are in AV-sync and | |
261 // we may need to insert sync-packets. We don't check |av_sync_| as we are | |
262 // outside AcmReceiver's critical section. | |
263 if (missing_packets_sync_stream_.get()) { | |
264 InsertStreamOfSyncPackets(missing_packets_sync_stream_.get()); | |
265 } | |
266 | |
267 if (neteq_->InsertPacket(rtp_header, incoming_payload, length_payload, | 197 if (neteq_->InsertPacket(rtp_header, incoming_payload, length_payload, |
268 receive_timestamp) < 0) { | 198 receive_timestamp) < 0) { |
269 LOG(LERROR) << "AcmReceiver::InsertPacket " | 199 LOG(LERROR) << "AcmReceiver::InsertPacket " |
270 << static_cast<int>(header->payloadType) | 200 << static_cast<int>(header->payloadType) |
271 << " Failed to insert packet"; | 201 << " Failed to insert packet"; |
272 return -1; | 202 return -1; |
273 } | 203 } |
274 return 0; | 204 return 0; |
275 } | 205 } |
276 | 206 |
277 int AcmReceiver::GetAudio(int desired_freq_hz, AudioFrame* audio_frame) { | 207 int AcmReceiver::GetAudio(int desired_freq_hz, AudioFrame* audio_frame) { |
278 enum NetEqOutputType type; | 208 enum NetEqOutputType type; |
279 size_t samples_per_channel; | 209 size_t samples_per_channel; |
280 int num_channels; | 210 int num_channels; |
281 bool return_silence = false; | |
282 | |
283 { | |
284 // Accessing members, take the lock. | |
285 CriticalSectionScoped lock(crit_sect_.get()); | |
286 | |
287 if (av_sync_) { | |
288 assert(initial_delay_manager_.get()); | |
289 assert(late_packets_sync_stream_.get()); | |
290 return_silence = GetSilence(desired_freq_hz, audio_frame); | |
291 uint32_t timestamp_now = NowInTimestamp(current_sample_rate_hz_); | |
292 initial_delay_manager_->LatePackets(timestamp_now, | |
293 late_packets_sync_stream_.get()); | |
294 } | |
295 } | |
296 | |
297 // If |late_packets_sync_stream_| is allocated then we have been in AV-sync | |
298 // mode and we might have to insert sync-packets. | |
299 if (late_packets_sync_stream_.get()) { | |
300 InsertStreamOfSyncPackets(late_packets_sync_stream_.get()); | |
301 if (return_silence) // Silence generated, don't pull from NetEq. | |
302 return 0; | |
303 } | |
304 | 211 |
305 // Accessing members, take the lock. | 212 // Accessing members, take the lock. |
306 CriticalSectionScoped lock(crit_sect_.get()); | 213 CriticalSectionScoped lock(crit_sect_.get()); |
307 | 214 |
308 // Always write the output to |audio_buffer_| first. | 215 // Always write the output to |audio_buffer_| first. |
309 if (neteq_->GetAudio(AudioFrame::kMaxDataSizeSamples, | 216 if (neteq_->GetAudio(AudioFrame::kMaxDataSizeSamples, |
310 audio_buffer_.get(), | 217 audio_buffer_.get(), |
311 &samples_per_channel, | 218 &samples_per_channel, |
312 &num_channels, | 219 &num_channels, |
313 &type) != NetEq::kOK) { | 220 &type) != NetEq::kOK) { |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
512 decoders_.erase(it); | 419 decoders_.erase(it); |
513 return 0; | 420 return 0; |
514 } | 421 } |
515 | 422 |
516 void AcmReceiver::set_id(int id) { | 423 void AcmReceiver::set_id(int id) { |
517 CriticalSectionScoped lock(crit_sect_.get()); | 424 CriticalSectionScoped lock(crit_sect_.get()); |
518 id_ = id; | 425 id_ = id; |
519 } | 426 } |
520 | 427 |
521 bool AcmReceiver::GetPlayoutTimestamp(uint32_t* timestamp) { | 428 bool AcmReceiver::GetPlayoutTimestamp(uint32_t* timestamp) { |
522 if (av_sync_) { | |
523 assert(initial_delay_manager_.get()); | |
524 if (initial_delay_manager_->buffering()) { | |
525 return initial_delay_manager_->GetPlayoutTimestamp(timestamp); | |
526 } | |
527 } | |
528 return neteq_->GetPlayoutTimestamp(timestamp); | 429 return neteq_->GetPlayoutTimestamp(timestamp); |
529 } | 430 } |
530 | 431 |
531 int AcmReceiver::last_audio_codec_id() const { | 432 int AcmReceiver::last_audio_codec_id() const { |
532 CriticalSectionScoped lock(crit_sect_.get()); | 433 CriticalSectionScoped lock(crit_sect_.get()); |
533 return last_audio_decoder_ ? last_audio_decoder_->acm_codec_id : -1; | 434 return last_audio_decoder_ ? last_audio_decoder_->acm_codec_id : -1; |
534 } | 435 } |
535 | 436 |
536 int AcmReceiver::LastAudioCodec(CodecInst* codec) const { | 437 int AcmReceiver::LastAudioCodec(CodecInst* codec) const { |
537 CriticalSectionScoped lock(crit_sect_.get()); | 438 CriticalSectionScoped lock(crit_sect_.get()); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
595 void AcmReceiver::DisableNack() { | 496 void AcmReceiver::DisableNack() { |
596 neteq_->DisableNack(); | 497 neteq_->DisableNack(); |
597 } | 498 } |
598 | 499 |
599 std::vector<uint16_t> AcmReceiver::GetNackList( | 500 std::vector<uint16_t> AcmReceiver::GetNackList( |
600 int64_t round_trip_time_ms) const { | 501 int64_t round_trip_time_ms) const { |
601 return neteq_->GetNackList(round_trip_time_ms); | 502 return neteq_->GetNackList(round_trip_time_ms); |
602 } | 503 } |
603 | 504 |
604 void AcmReceiver::ResetInitialDelay() { | 505 void AcmReceiver::ResetInitialDelay() { |
605 { | |
606 CriticalSectionScoped lock(crit_sect_.get()); | |
607 av_sync_ = false; | |
608 initial_delay_manager_.reset(NULL); | |
609 missing_packets_sync_stream_.reset(NULL); | |
610 late_packets_sync_stream_.reset(NULL); | |
611 } | |
612 neteq_->SetMinimumDelay(0); | 506 neteq_->SetMinimumDelay(0); |
613 // TODO(turajs): Should NetEq Buffer be flushed? | 507 // TODO(turajs): Should NetEq Buffer be flushed? |
614 } | 508 } |
615 | 509 |
616 // This function is called within critical section, no need to acquire a lock. | |
617 bool AcmReceiver::GetSilence(int desired_sample_rate_hz, AudioFrame* frame) { | |
618 assert(av_sync_); | |
619 assert(initial_delay_manager_.get()); | |
620 if (!initial_delay_manager_->buffering()) { | |
621 return false; | |
622 } | |
623 | |
624 // We stop accumulating packets, if the number of packets or the total size | |
625 // exceeds a threshold. | |
626 int num_packets; | |
627 int max_num_packets; | |
628 const float kBufferingThresholdScale = 0.9f; | |
629 neteq_->PacketBufferStatistics(&num_packets, &max_num_packets); | |
630 if (num_packets > max_num_packets * kBufferingThresholdScale) { | |
631 initial_delay_manager_->DisableBuffering(); | |
632 return false; | |
633 } | |
634 | |
635 // Update statistics. | |
636 call_stats_.DecodedBySilenceGenerator(); | |
637 | |
638 // Set the values if already got a packet, otherwise set to default values. | |
639 if (last_audio_decoder_) { | |
640 current_sample_rate_hz_ = | |
641 ACMCodecDB::database_[last_audio_decoder_->acm_codec_id].plfreq; | |
642 frame->num_channels_ = last_audio_decoder_->channels; | |
643 } else { | |
644 frame->num_channels_ = 1; | |
645 } | |
646 | |
647 // Set the audio frame's sampling frequency. | |
648 if (desired_sample_rate_hz > 0) { | |
649 frame->sample_rate_hz_ = desired_sample_rate_hz; | |
650 } else { | |
651 frame->sample_rate_hz_ = current_sample_rate_hz_; | |
652 } | |
653 | |
654 frame->samples_per_channel_ = | |
655 static_cast<size_t>(frame->sample_rate_hz_ / 100); // Always 10 ms. | |
656 frame->speech_type_ = AudioFrame::kCNG; | |
657 frame->vad_activity_ = AudioFrame::kVadPassive; | |
658 size_t samples = frame->samples_per_channel_ * frame->num_channels_; | |
659 memset(frame->data_, 0, samples * sizeof(int16_t)); | |
660 return true; | |
661 } | |
662 | |
663 const AcmReceiver::Decoder* AcmReceiver::RtpHeaderToDecoder( | 510 const AcmReceiver::Decoder* AcmReceiver::RtpHeaderToDecoder( |
664 const RTPHeader& rtp_header, | 511 const RTPHeader& rtp_header, |
665 const uint8_t* payload) const { | 512 const uint8_t* payload) const { |
666 auto it = decoders_.find(rtp_header.payloadType); | 513 auto it = decoders_.find(rtp_header.payloadType); |
667 const auto red_index = | 514 const auto red_index = |
668 RentACodec::CodecIndexFromId(RentACodec::CodecId::kRED); | 515 RentACodec::CodecIndexFromId(RentACodec::CodecId::kRED); |
669 if (red_index && // This ensures that RED is defined in WebRTC. | 516 if (red_index && // This ensures that RED is defined in WebRTC. |
670 it != decoders_.end() && it->second.acm_codec_id == *red_index) { | 517 it != decoders_.end() && it->second.acm_codec_id == *red_index) { |
671 // This is a RED packet, get the payload of the audio codec. | 518 // This is a RED packet, get the payload of the audio codec. |
672 it = decoders_.find(payload[0] & 0x7F); | 519 it = decoders_.find(payload[0] & 0x7F); |
673 } | 520 } |
674 | 521 |
675 // Check if the payload is registered. | 522 // Check if the payload is registered. |
676 return it != decoders_.end() ? &it->second : nullptr; | 523 return it != decoders_.end() ? &it->second : nullptr; |
677 } | 524 } |
678 | 525 |
679 uint32_t AcmReceiver::NowInTimestamp(int decoder_sampling_rate) const { | 526 uint32_t AcmReceiver::NowInTimestamp(int decoder_sampling_rate) const { |
680 // Down-cast the time to (32-6)-bit since we only care about | 527 // Down-cast the time to (32-6)-bit since we only care about |
681 // the least significant bits. (32-6) bits cover 2^(32-6) = 67108864 ms. | 528 // the least significant bits. (32-6) bits cover 2^(32-6) = 67108864 ms. |
682 // We masked 6 most significant bits of 32-bit so there is no overflow in | 529 // We masked 6 most significant bits of 32-bit so there is no overflow in |
683 // the conversion from milliseconds to timestamp. | 530 // the conversion from milliseconds to timestamp. |
684 const uint32_t now_in_ms = static_cast<uint32_t>( | 531 const uint32_t now_in_ms = static_cast<uint32_t>( |
685 clock_->TimeInMilliseconds() & 0x03ffffff); | 532 clock_->TimeInMilliseconds() & 0x03ffffff); |
686 return static_cast<uint32_t>( | 533 return static_cast<uint32_t>( |
687 (decoder_sampling_rate / 1000) * now_in_ms); | 534 (decoder_sampling_rate / 1000) * now_in_ms); |
688 } | 535 } |
689 | 536 |
690 // This function only interacts with |neteq_|, therefore, it does not have to | |
691 // be within critical section of AcmReceiver. It is inserting packets | |
692 // into NetEq, so we call it when |decode_lock_| is acquired. However, this is | |
693 // not essential as sync-packets do not interact with codecs (especially BWE). | |
694 void AcmReceiver::InsertStreamOfSyncPackets( | |
695 InitialDelayManager::SyncStream* sync_stream) { | |
696 assert(sync_stream); | |
697 assert(av_sync_); | |
698 for (int n = 0; n < sync_stream->num_sync_packets; ++n) { | |
699 neteq_->InsertSyncPacket(sync_stream->rtp_info, | |
700 sync_stream->receive_timestamp); | |
701 ++sync_stream->rtp_info.header.sequenceNumber; | |
702 sync_stream->rtp_info.header.timestamp += sync_stream->timestamp_step; | |
703 sync_stream->receive_timestamp += sync_stream->timestamp_step; | |
704 } | |
705 } | |
706 | |
707 void AcmReceiver::GetDecodingCallStatistics( | 537 void AcmReceiver::GetDecodingCallStatistics( |
708 AudioDecodingCallStats* stats) const { | 538 AudioDecodingCallStats* stats) const { |
709 CriticalSectionScoped lock(crit_sect_.get()); | 539 CriticalSectionScoped lock(crit_sect_.get()); |
710 *stats = call_stats_.GetDecodingStatistics(); | 540 *stats = call_stats_.GetDecodingStatistics(); |
711 } | 541 } |
712 | 542 |
713 } // namespace acm2 | 543 } // namespace acm2 |
714 | 544 |
715 } // namespace webrtc | 545 } // namespace webrtc |
OLD | NEW |