| 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/acm2/acm_receiver.h" | 11 #include "webrtc/modules/audio_coding/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/acm2/acm_resampler.h" | 24 #include "webrtc/modules/audio_coding/acm2/acm_resampler.h" |
| 25 #include "webrtc/modules/audio_coding/acm2/call_statistics.h" | 25 #include "webrtc/modules/audio_coding/acm2/call_statistics.h" |
| 26 #include "webrtc/modules/audio_coding/neteq/include/neteq.h" | 26 #include "webrtc/modules/audio_coding/neteq/include/neteq.h" |
| 27 #include "webrtc/system_wrappers/include/clock.h" | 27 #include "webrtc/system_wrappers/include/clock.h" |
| 28 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | |
| 29 #include "webrtc/system_wrappers/include/tick_util.h" | 28 #include "webrtc/system_wrappers/include/tick_util.h" |
| 30 #include "webrtc/system_wrappers/include/trace.h" | 29 #include "webrtc/system_wrappers/include/trace.h" |
| 31 | 30 |
| 32 namespace webrtc { | 31 namespace webrtc { |
| 33 | 32 |
| 34 namespace acm2 { | 33 namespace acm2 { |
| 35 | 34 |
| 36 namespace { | 35 namespace { |
| 37 | 36 |
| 38 // |vad_activity_| field of |audio_frame| is set to |previous_audio_activity_| | 37 // |vad_activity_| field of |audio_frame| is set to |previous_audio_activity_| |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 auto i = RentACodec::CodecIdFromIndex(codec_id); | 111 auto i = RentACodec::CodecIdFromIndex(codec_id); |
| 113 return (i && (*i == RentACodec::CodecId::kCNNB || | 112 return (i && (*i == RentACodec::CodecId::kCNNB || |
| 114 *i == RentACodec::CodecId::kCNWB || | 113 *i == RentACodec::CodecId::kCNWB || |
| 115 *i == RentACodec::CodecId::kCNSWB || | 114 *i == RentACodec::CodecId::kCNSWB || |
| 116 *i == RentACodec::CodecId::kCNFB)); | 115 *i == RentACodec::CodecId::kCNFB)); |
| 117 } | 116 } |
| 118 | 117 |
| 119 } // namespace | 118 } // namespace |
| 120 | 119 |
| 121 AcmReceiver::AcmReceiver(const AudioCodingModule::Config& config) | 120 AcmReceiver::AcmReceiver(const AudioCodingModule::Config& config) |
| 122 : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), | 121 : id_(config.id), |
| 123 id_(config.id), | |
| 124 last_audio_decoder_(nullptr), | 122 last_audio_decoder_(nullptr), |
| 125 previous_audio_activity_(AudioFrame::kVadPassive), | 123 previous_audio_activity_(AudioFrame::kVadPassive), |
| 126 audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]), | 124 audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]), |
| 127 last_audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]), | 125 last_audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]), |
| 128 neteq_(NetEq::Create(config.neteq_config)), | 126 neteq_(NetEq::Create(config.neteq_config)), |
| 129 vad_enabled_(config.neteq_config.enable_post_decode_vad), | 127 vad_enabled_(config.neteq_config.enable_post_decode_vad), |
| 130 clock_(config.clock), | 128 clock_(config.clock), |
| 131 resampled_last_output_frame_(true) { | 129 resampled_last_output_frame_(true) { |
| 132 assert(clock_); | 130 assert(clock_); |
| 133 memset(audio_buffer_.get(), 0, AudioFrame::kMaxDataSizeSamples); | 131 memset(audio_buffer_.get(), 0, AudioFrame::kMaxDataSizeSamples); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 150 return 0; | 148 return 0; |
| 151 LOG(LERROR) << "AcmReceiver::SetExtraDelay " << delay_ms; | 149 LOG(LERROR) << "AcmReceiver::SetExtraDelay " << delay_ms; |
| 152 return -1; | 150 return -1; |
| 153 } | 151 } |
| 154 | 152 |
| 155 int AcmReceiver::LeastRequiredDelayMs() const { | 153 int AcmReceiver::LeastRequiredDelayMs() const { |
| 156 return neteq_->LeastRequiredDelayMs(); | 154 return neteq_->LeastRequiredDelayMs(); |
| 157 } | 155 } |
| 158 | 156 |
| 159 rtc::Optional<int> AcmReceiver::last_packet_sample_rate_hz() const { | 157 rtc::Optional<int> AcmReceiver::last_packet_sample_rate_hz() const { |
| 160 CriticalSectionScoped lock(crit_sect_.get()); | 158 rtc::CritScope lock(&crit_sect_); |
| 161 return last_packet_sample_rate_hz_; | 159 return last_packet_sample_rate_hz_; |
| 162 } | 160 } |
| 163 | 161 |
| 164 int AcmReceiver::last_output_sample_rate_hz() const { | 162 int AcmReceiver::last_output_sample_rate_hz() const { |
| 165 return neteq_->last_output_sample_rate_hz(); | 163 return neteq_->last_output_sample_rate_hz(); |
| 166 } | 164 } |
| 167 | 165 |
| 168 int AcmReceiver::InsertPacket(const WebRtcRTPHeader& rtp_header, | 166 int AcmReceiver::InsertPacket(const WebRtcRTPHeader& rtp_header, |
| 169 rtc::ArrayView<const uint8_t> incoming_payload) { | 167 rtc::ArrayView<const uint8_t> incoming_payload) { |
| 170 uint32_t receive_timestamp = 0; | 168 uint32_t receive_timestamp = 0; |
| 171 const RTPHeader* header = &rtp_header.header; // Just a shorthand. | 169 const RTPHeader* header = &rtp_header.header; // Just a shorthand. |
| 172 | 170 |
| 173 { | 171 { |
| 174 CriticalSectionScoped lock(crit_sect_.get()); | 172 rtc::CritScope lock(&crit_sect_); |
| 175 | 173 |
| 176 const Decoder* decoder = RtpHeaderToDecoder(*header, incoming_payload[0]); | 174 const Decoder* decoder = RtpHeaderToDecoder(*header, incoming_payload[0]); |
| 177 if (!decoder) { | 175 if (!decoder) { |
| 178 LOG_F(LS_ERROR) << "Payload-type " | 176 LOG_F(LS_ERROR) << "Payload-type " |
| 179 << static_cast<int>(header->payloadType) | 177 << static_cast<int>(header->payloadType) |
| 180 << " is not registered."; | 178 << " is not registered."; |
| 181 return -1; | 179 return -1; |
| 182 } | 180 } |
| 183 const int sample_rate_hz = [&decoder] { | 181 const int sample_rate_hz = [&decoder] { |
| 184 const auto ci = RentACodec::CodecIdFromIndex(decoder->acm_codec_id); | 182 const auto ci = RentACodec::CodecIdFromIndex(decoder->acm_codec_id); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 209 } | 207 } |
| 210 return 0; | 208 return 0; |
| 211 } | 209 } |
| 212 | 210 |
| 213 int AcmReceiver::GetAudio(int desired_freq_hz, AudioFrame* audio_frame) { | 211 int AcmReceiver::GetAudio(int desired_freq_hz, AudioFrame* audio_frame) { |
| 214 enum NetEqOutputType type; | 212 enum NetEqOutputType type; |
| 215 size_t samples_per_channel; | 213 size_t samples_per_channel; |
| 216 size_t num_channels; | 214 size_t num_channels; |
| 217 | 215 |
| 218 // Accessing members, take the lock. | 216 // Accessing members, take the lock. |
| 219 CriticalSectionScoped lock(crit_sect_.get()); | 217 rtc::CritScope lock(&crit_sect_); |
| 220 | 218 |
| 221 // Always write the output to |audio_buffer_| first. | 219 // Always write the output to |audio_buffer_| first. |
| 222 if (neteq_->GetAudio(AudioFrame::kMaxDataSizeSamples, | 220 if (neteq_->GetAudio(AudioFrame::kMaxDataSizeSamples, |
| 223 audio_buffer_.get(), | 221 audio_buffer_.get(), |
| 224 &samples_per_channel, | 222 &samples_per_channel, |
| 225 &num_channels, | 223 &num_channels, |
| 226 &type) != NetEq::kOK) { | 224 &type) != NetEq::kOK) { |
| 227 LOG(LERROR) << "AcmReceiver::GetAudio - NetEq Failed."; | 225 LOG(LERROR) << "AcmReceiver::GetAudio - NetEq Failed."; |
| 228 return -1; | 226 return -1; |
| 229 } | 227 } |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 return NetEqDecoder::kDecoderArbitrary; // External decoder. | 308 return NetEqDecoder::kDecoderArbitrary; // External decoder. |
| 311 const rtc::Optional<RentACodec::CodecId> cid = | 309 const rtc::Optional<RentACodec::CodecId> cid = |
| 312 RentACodec::CodecIdFromIndex(acm_codec_id); | 310 RentACodec::CodecIdFromIndex(acm_codec_id); |
| 313 RTC_DCHECK(cid) << "Invalid codec index: " << acm_codec_id; | 311 RTC_DCHECK(cid) << "Invalid codec index: " << acm_codec_id; |
| 314 const rtc::Optional<NetEqDecoder> ned = | 312 const rtc::Optional<NetEqDecoder> ned = |
| 315 RentACodec::NetEqDecoderFromCodecId(*cid, channels); | 313 RentACodec::NetEqDecoderFromCodecId(*cid, channels); |
| 316 RTC_DCHECK(ned) << "Invalid codec ID: " << static_cast<int>(*cid); | 314 RTC_DCHECK(ned) << "Invalid codec ID: " << static_cast<int>(*cid); |
| 317 return *ned; | 315 return *ned; |
| 318 }(); | 316 }(); |
| 319 | 317 |
| 320 CriticalSectionScoped lock(crit_sect_.get()); | 318 rtc::CritScope lock(&crit_sect_); |
| 321 | 319 |
| 322 // The corresponding NetEq decoder ID. | 320 // The corresponding NetEq decoder ID. |
| 323 // If this codec has been registered before. | 321 // If this codec has been registered before. |
| 324 auto it = decoders_.find(payload_type); | 322 auto it = decoders_.find(payload_type); |
| 325 if (it != decoders_.end()) { | 323 if (it != decoders_.end()) { |
| 326 const Decoder& decoder = it->second; | 324 const Decoder& decoder = it->second; |
| 327 if (acm_codec_id != -1 && decoder.acm_codec_id == acm_codec_id && | 325 if (acm_codec_id != -1 && decoder.acm_codec_id == acm_codec_id && |
| 328 decoder.channels == channels && | 326 decoder.channels == channels && |
| 329 decoder.sample_rate_hz == sample_rate_hz) { | 327 decoder.sample_rate_hz == sample_rate_hz) { |
| 330 // Re-registering the same codec. Do nothing and return. | 328 // Re-registering the same codec. Do nothing and return. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 359 decoder.acm_codec_id = acm_codec_id; | 357 decoder.acm_codec_id = acm_codec_id; |
| 360 decoder.payload_type = payload_type; | 358 decoder.payload_type = payload_type; |
| 361 decoder.channels = channels; | 359 decoder.channels = channels; |
| 362 decoder.sample_rate_hz = sample_rate_hz; | 360 decoder.sample_rate_hz = sample_rate_hz; |
| 363 decoders_[payload_type] = decoder; | 361 decoders_[payload_type] = decoder; |
| 364 return 0; | 362 return 0; |
| 365 } | 363 } |
| 366 | 364 |
| 367 void AcmReceiver::EnableVad() { | 365 void AcmReceiver::EnableVad() { |
| 368 neteq_->EnableVad(); | 366 neteq_->EnableVad(); |
| 369 CriticalSectionScoped lock(crit_sect_.get()); | 367 rtc::CritScope lock(&crit_sect_); |
| 370 vad_enabled_ = true; | 368 vad_enabled_ = true; |
| 371 } | 369 } |
| 372 | 370 |
| 373 void AcmReceiver::DisableVad() { | 371 void AcmReceiver::DisableVad() { |
| 374 neteq_->DisableVad(); | 372 neteq_->DisableVad(); |
| 375 CriticalSectionScoped lock(crit_sect_.get()); | 373 rtc::CritScope lock(&crit_sect_); |
| 376 vad_enabled_ = false; | 374 vad_enabled_ = false; |
| 377 } | 375 } |
| 378 | 376 |
| 379 void AcmReceiver::FlushBuffers() { | 377 void AcmReceiver::FlushBuffers() { |
| 380 neteq_->FlushBuffers(); | 378 neteq_->FlushBuffers(); |
| 381 } | 379 } |
| 382 | 380 |
| 383 // If failed in removing one of the codecs, this method continues to remove as | 381 // If failed in removing one of the codecs, this method continues to remove as |
| 384 // many as it can. | 382 // many as it can. |
| 385 int AcmReceiver::RemoveAllCodecs() { | 383 int AcmReceiver::RemoveAllCodecs() { |
| 386 int ret_val = 0; | 384 int ret_val = 0; |
| 387 CriticalSectionScoped lock(crit_sect_.get()); | 385 rtc::CritScope lock(&crit_sect_); |
| 388 for (auto it = decoders_.begin(); it != decoders_.end(); ) { | 386 for (auto it = decoders_.begin(); it != decoders_.end(); ) { |
| 389 auto cur = it; | 387 auto cur = it; |
| 390 ++it; // it will be valid even if we erase cur | 388 ++it; // it will be valid even if we erase cur |
| 391 if (neteq_->RemovePayloadType(cur->second.payload_type) == 0) { | 389 if (neteq_->RemovePayloadType(cur->second.payload_type) == 0) { |
| 392 decoders_.erase(cur); | 390 decoders_.erase(cur); |
| 393 } else { | 391 } else { |
| 394 LOG_F(LS_ERROR) << "Cannot remove payload " | 392 LOG_F(LS_ERROR) << "Cannot remove payload " |
| 395 << static_cast<int>(cur->second.payload_type); | 393 << static_cast<int>(cur->second.payload_type); |
| 396 ret_val = -1; | 394 ret_val = -1; |
| 397 } | 395 } |
| 398 } | 396 } |
| 399 | 397 |
| 400 // No codec is registered, invalidate last audio decoder. | 398 // No codec is registered, invalidate last audio decoder. |
| 401 last_audio_decoder_ = nullptr; | 399 last_audio_decoder_ = nullptr; |
| 402 last_packet_sample_rate_hz_ = rtc::Optional<int>(); | 400 last_packet_sample_rate_hz_ = rtc::Optional<int>(); |
| 403 return ret_val; | 401 return ret_val; |
| 404 } | 402 } |
| 405 | 403 |
| 406 int AcmReceiver::RemoveCodec(uint8_t payload_type) { | 404 int AcmReceiver::RemoveCodec(uint8_t payload_type) { |
| 407 CriticalSectionScoped lock(crit_sect_.get()); | 405 rtc::CritScope lock(&crit_sect_); |
| 408 auto it = decoders_.find(payload_type); | 406 auto it = decoders_.find(payload_type); |
| 409 if (it == decoders_.end()) { // Such a payload-type is not registered. | 407 if (it == decoders_.end()) { // Such a payload-type is not registered. |
| 410 return 0; | 408 return 0; |
| 411 } | 409 } |
| 412 if (neteq_->RemovePayloadType(payload_type) != NetEq::kOK) { | 410 if (neteq_->RemovePayloadType(payload_type) != NetEq::kOK) { |
| 413 LOG(LERROR) << "AcmReceiver::RemoveCodec" << static_cast<int>(payload_type); | 411 LOG(LERROR) << "AcmReceiver::RemoveCodec" << static_cast<int>(payload_type); |
| 414 return -1; | 412 return -1; |
| 415 } | 413 } |
| 416 if (last_audio_decoder_ == &it->second) { | 414 if (last_audio_decoder_ == &it->second) { |
| 417 last_audio_decoder_ = nullptr; | 415 last_audio_decoder_ = nullptr; |
| 418 last_packet_sample_rate_hz_ = rtc::Optional<int>(); | 416 last_packet_sample_rate_hz_ = rtc::Optional<int>(); |
| 419 } | 417 } |
| 420 decoders_.erase(it); | 418 decoders_.erase(it); |
| 421 return 0; | 419 return 0; |
| 422 } | 420 } |
| 423 | 421 |
| 424 void AcmReceiver::set_id(int id) { | 422 void AcmReceiver::set_id(int id) { |
| 425 CriticalSectionScoped lock(crit_sect_.get()); | 423 rtc::CritScope lock(&crit_sect_); |
| 426 id_ = id; | 424 id_ = id; |
| 427 } | 425 } |
| 428 | 426 |
| 429 bool AcmReceiver::GetPlayoutTimestamp(uint32_t* timestamp) { | 427 bool AcmReceiver::GetPlayoutTimestamp(uint32_t* timestamp) { |
| 430 return neteq_->GetPlayoutTimestamp(timestamp); | 428 return neteq_->GetPlayoutTimestamp(timestamp); |
| 431 } | 429 } |
| 432 | 430 |
| 433 int AcmReceiver::LastAudioCodec(CodecInst* codec) const { | 431 int AcmReceiver::LastAudioCodec(CodecInst* codec) const { |
| 434 CriticalSectionScoped lock(crit_sect_.get()); | 432 rtc::CritScope lock(&crit_sect_); |
| 435 if (!last_audio_decoder_) { | 433 if (!last_audio_decoder_) { |
| 436 return -1; | 434 return -1; |
| 437 } | 435 } |
| 438 *codec = *RentACodec::CodecInstById( | 436 *codec = *RentACodec::CodecInstById( |
| 439 *RentACodec::CodecIdFromIndex(last_audio_decoder_->acm_codec_id)); | 437 *RentACodec::CodecIdFromIndex(last_audio_decoder_->acm_codec_id)); |
| 440 codec->pltype = last_audio_decoder_->payload_type; | 438 codec->pltype = last_audio_decoder_->payload_type; |
| 441 codec->channels = last_audio_decoder_->channels; | 439 codec->channels = last_audio_decoder_->channels; |
| 442 codec->plfreq = last_audio_decoder_->sample_rate_hz; | 440 codec->plfreq = last_audio_decoder_->sample_rate_hz; |
| 443 return 0; | 441 return 0; |
| 444 } | 442 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 461 acm_stat->clockDriftPPM = neteq_stat.clockdrift_ppm; | 459 acm_stat->clockDriftPPM = neteq_stat.clockdrift_ppm; |
| 462 acm_stat->addedSamples = neteq_stat.added_zero_samples; | 460 acm_stat->addedSamples = neteq_stat.added_zero_samples; |
| 463 acm_stat->meanWaitingTimeMs = neteq_stat.mean_waiting_time_ms; | 461 acm_stat->meanWaitingTimeMs = neteq_stat.mean_waiting_time_ms; |
| 464 acm_stat->medianWaitingTimeMs = neteq_stat.median_waiting_time_ms; | 462 acm_stat->medianWaitingTimeMs = neteq_stat.median_waiting_time_ms; |
| 465 acm_stat->minWaitingTimeMs = neteq_stat.min_waiting_time_ms; | 463 acm_stat->minWaitingTimeMs = neteq_stat.min_waiting_time_ms; |
| 466 acm_stat->maxWaitingTimeMs = neteq_stat.max_waiting_time_ms; | 464 acm_stat->maxWaitingTimeMs = neteq_stat.max_waiting_time_ms; |
| 467 } | 465 } |
| 468 | 466 |
| 469 int AcmReceiver::DecoderByPayloadType(uint8_t payload_type, | 467 int AcmReceiver::DecoderByPayloadType(uint8_t payload_type, |
| 470 CodecInst* codec) const { | 468 CodecInst* codec) const { |
| 471 CriticalSectionScoped lock(crit_sect_.get()); | 469 rtc::CritScope lock(&crit_sect_); |
| 472 auto it = decoders_.find(payload_type); | 470 auto it = decoders_.find(payload_type); |
| 473 if (it == decoders_.end()) { | 471 if (it == decoders_.end()) { |
| 474 LOG(LERROR) << "AcmReceiver::DecoderByPayloadType " | 472 LOG(LERROR) << "AcmReceiver::DecoderByPayloadType " |
| 475 << static_cast<int>(payload_type); | 473 << static_cast<int>(payload_type); |
| 476 return -1; | 474 return -1; |
| 477 } | 475 } |
| 478 const Decoder& decoder = it->second; | 476 const Decoder& decoder = it->second; |
| 479 *codec = *RentACodec::CodecInstById( | 477 *codec = *RentACodec::CodecInstById( |
| 480 *RentACodec::CodecIdFromIndex(decoder.acm_codec_id)); | 478 *RentACodec::CodecIdFromIndex(decoder.acm_codec_id)); |
| 481 codec->pltype = decoder.payload_type; | 479 codec->pltype = decoder.payload_type; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 // We masked 6 most significant bits of 32-bit so there is no overflow in | 523 // We masked 6 most significant bits of 32-bit so there is no overflow in |
| 526 // the conversion from milliseconds to timestamp. | 524 // the conversion from milliseconds to timestamp. |
| 527 const uint32_t now_in_ms = static_cast<uint32_t>( | 525 const uint32_t now_in_ms = static_cast<uint32_t>( |
| 528 clock_->TimeInMilliseconds() & 0x03ffffff); | 526 clock_->TimeInMilliseconds() & 0x03ffffff); |
| 529 return static_cast<uint32_t>( | 527 return static_cast<uint32_t>( |
| 530 (decoder_sampling_rate / 1000) * now_in_ms); | 528 (decoder_sampling_rate / 1000) * now_in_ms); |
| 531 } | 529 } |
| 532 | 530 |
| 533 void AcmReceiver::GetDecodingCallStatistics( | 531 void AcmReceiver::GetDecodingCallStatistics( |
| 534 AudioDecodingCallStats* stats) const { | 532 AudioDecodingCallStats* stats) const { |
| 535 CriticalSectionScoped lock(crit_sect_.get()); | 533 rtc::CritScope lock(&crit_sect_); |
| 536 *stats = call_stats_.GetDecodingStatistics(); | 534 *stats = call_stats_.GetDecodingStatistics(); |
| 537 } | 535 } |
| 538 | 536 |
| 539 } // namespace acm2 | 537 } // namespace acm2 |
| 540 | 538 |
| 541 } // namespace webrtc | 539 } // namespace webrtc |
| OLD | NEW |