AcmReceiver: use std::map instead of an array to keep the list of decoders
R=kwiberg@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/50419004
Cr-Original-Commit-Position: refs/heads/master@{#8824}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: a4bef3e6c04e865e1a738286a76eac18ed0f24e8
diff --git a/modules/audio_coding/main/acm2/acm_receiver.cc b/modules/audio_coding/main/acm2/acm_receiver.cc
index 5041eb7..64a2f51 100644
--- a/modules/audio_coding/main/acm2/acm_receiver.cc
+++ b/modules/audio_coding/main/acm2/acm_receiver.cc
@@ -15,6 +15,7 @@
#include <algorithm> // sort
#include <vector>
+#include "webrtc/base/checks.h"
#include "webrtc/base/format_macros.h"
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
#include "webrtc/common_types.h"
@@ -136,9 +137,6 @@
missing_packets_sync_stream_(),
late_packets_sync_stream_() {
assert(clock_);
- for (int n = 0; n < ACMCodecDB::kMaxNumCodecs; ++n) {
- decoders_[n].registered = false;
- }
// Make sure we are on the same page as NetEq. Post-decode VAD is disabled by
// default in NetEq4, however, Audio Conference Mixer relies on VAD decision
@@ -279,7 +277,6 @@
<< " is not registered.";
return -1;
}
- assert(codec_id < ACMCodecDB::kMaxNumCodecs);
const int sample_rate_hz = ACMCodecDB::CodecFreq(codec_id);
receive_timestamp = NowInTimestamp(sample_rate_hz);
@@ -483,7 +480,7 @@
uint8_t payload_type,
int channels,
AudioDecoder* audio_decoder) {
- assert(acm_codec_id >= 0 && acm_codec_id < ACMCodecDB::kMaxNumCodecs);
+ CHECK_GE(acm_codec_id, 0);
NetEqDecoder neteq_decoder = ACMCodecDB::neteq_decoders_[acm_codec_id];
// Make sure the right decoder is registered for Opus.
@@ -494,10 +491,12 @@
CriticalSectionScoped lock(crit_sect_.get());
// The corresponding NetEq decoder ID.
- // If this coder has been registered before.
- if (decoders_[acm_codec_id].registered) {
- if (decoders_[acm_codec_id].payload_type == payload_type &&
- decoders_[acm_codec_id].channels == channels) {
+ // If this codec has been registered before.
+ auto it = decoders_.find(acm_codec_id);
+ if (it != decoders_.end()) {
+ const Decoder& decoder = it->second;
+ if (decoder.payload_type == payload_type &&
+ decoder.channels == channels) {
// Re-registering the same codec with the same payload-type. Do nothing
// and return.
return 0;
@@ -505,12 +504,14 @@
// Changing the payload-type or number of channels for this codec.
// First unregister. Then register with new payload-type/channels.
- if (neteq_->RemovePayloadType(decoders_[acm_codec_id].payload_type) !=
+ if (neteq_->RemovePayloadType(decoder.payload_type) !=
NetEq::kOK) {
LOG_F(LS_ERROR) << "Cannot remove payload "
- << static_cast<int>(decoders_[acm_codec_id].payload_type);
+ << static_cast<int>(decoder.payload_type);
return -1;
}
+
+ decoders_.erase(it);
}
int ret_val;
@@ -523,15 +524,14 @@
if (ret_val != NetEq::kOK) {
LOG_FERR3(LS_ERROR, "AcmReceiver::AddCodec", acm_codec_id,
static_cast<int>(payload_type), channels);
- // Registration failed, delete the allocated space and set the pointer to
- // NULL, for the record.
- decoders_[acm_codec_id].registered = false;
return -1;
}
- decoders_[acm_codec_id].registered = true;
- decoders_[acm_codec_id].payload_type = payload_type;
- decoders_[acm_codec_id].channels = channels;
+ Decoder decoder;
+ decoder.acm_codec_id = acm_codec_id;
+ decoder.payload_type = payload_type;
+ decoder.channels = channels;
+ decoders_[acm_codec_id] = decoder;
return 0;
}
@@ -556,23 +556,25 @@
int AcmReceiver::RemoveAllCodecs() {
int ret_val = 0;
CriticalSectionScoped lock(crit_sect_.get());
- for (int n = 0; n < ACMCodecDB::kMaxNumCodecs; ++n) {
- if (decoders_[n].registered) {
- if (neteq_->RemovePayloadType(decoders_[n].payload_type) == 0) {
- decoders_[n].registered = false;
- } else {
- LOG_F(LS_ERROR) << "Cannot remove payload "
- << static_cast<int>(decoders_[n].payload_type);
- ret_val = -1;
- }
+ for (auto it = decoders_.begin(); it != decoders_.end(); ) {
+ auto cur = it;
+ ++it; // it will be valid even if we erase cur
+ if (neteq_->RemovePayloadType(cur->second.payload_type) == 0) {
+ decoders_.erase(cur);
+ } else {
+ LOG_F(LS_ERROR) << "Cannot remove payload "
+ << static_cast<int>(cur->second.payload_type);
+ ret_val = -1;
}
}
+
// No codec is registered, invalidate last audio decoder.
last_audio_decoder_ = -1;
return ret_val;
}
int AcmReceiver::RemoveCodec(uint8_t payload_type) {
+ CriticalSectionScoped lock(crit_sect_.get());
int codec_index = PayloadType2CodecIndex(payload_type);
if (codec_index < 0) { // Such a payload-type is not registered.
return 0;
@@ -582,8 +584,7 @@
static_cast<int>(payload_type));
return -1;
}
- CriticalSectionScoped lock(crit_sect_.get());
- decoders_[codec_index].registered = false;
+ decoders_.erase(codec_index);
if (last_audio_decoder_ == codec_index)
last_audio_decoder_ = -1; // Codec is removed, invalidate last decoder.
return 0;
@@ -611,12 +612,12 @@
int AcmReceiver::RedPayloadType() const {
CriticalSectionScoped lock(crit_sect_.get());
- if (ACMCodecDB::kRED < 0 ||
- !decoders_[ACMCodecDB::kRED].registered) {
+ auto it = decoders_.find(ACMCodecDB::kRED);
+ if (ACMCodecDB::kRED < 0 || it == decoders_.end()) {
LOG_F(LS_WARNING) << "RED is not registered.";
return -1;
}
- return decoders_[ACMCodecDB::kRED].payload_type;
+ return it->second.payload_type;
}
int AcmReceiver::LastAudioCodec(CodecInst* codec) const {
@@ -624,10 +625,11 @@
if (last_audio_decoder_ < 0) {
return -1;
}
- assert(decoders_[last_audio_decoder_].registered);
+ auto it = decoders_.find(last_audio_decoder_);
+ CHECK(it != decoders_.end());
memcpy(codec, &ACMCodecDB::database_[last_audio_decoder_], sizeof(CodecInst));
- codec->pltype = decoders_[last_audio_decoder_].payload_type;
- codec->channels = decoders_[last_audio_decoder_].channels;
+ codec->pltype = it->second.payload_type;
+ codec->channels = it->second.channels;
return 0;
}
@@ -685,16 +687,18 @@
return -1;
}
memcpy(codec, &ACMCodecDB::database_[codec_index], sizeof(CodecInst));
- codec->pltype = decoders_[codec_index].payload_type;
- codec->channels = decoders_[codec_index].channels;
+ // Safe not to check the iterator
+ const Decoder& decoder = decoders_.find(codec_index)->second;
+ codec->pltype = decoder.payload_type;
+ codec->channels = decoder.channels;
return 0;
}
int AcmReceiver::PayloadType2CodecIndex(uint8_t payload_type) const {
- for (int n = 0; n < ACMCodecDB::kMaxNumCodecs; ++n) {
- if (decoders_[n].registered && decoders_[n].payload_type == payload_type) {
- return n;
- }
+ for (const auto& decoder_pair : decoders_) {
+ const Decoder& decoder = decoder_pair.second;
+ if (decoder.payload_type == payload_type)
+ return decoder.acm_codec_id;
}
return -1;
}
@@ -801,9 +805,10 @@
int AcmReceiver::RtpHeaderToCodecIndex(
const RTPHeader &rtp_header, const uint8_t* payload) const {
uint8_t payload_type = rtp_header.payloadType;
+ auto it = decoders_.find(ACMCodecDB::kRED);
if (ACMCodecDB::kRED >= 0 && // This ensures that RED is defined in WebRTC.
- decoders_[ACMCodecDB::kRED].registered &&
- payload_type == decoders_[ACMCodecDB::kRED].payload_type) {
+ it != decoders_.end() &&
+ payload_type == it->second.payload_type) {
// This is a RED packet, get the payload of the audio codec.
payload_type = payload[0] & 0x7F;
}
diff --git a/modules/audio_coding/main/acm2/acm_receiver.h b/modules/audio_coding/main/acm2/acm_receiver.h
index f18cc51..f9f0d03 100644
--- a/modules/audio_coding/main/acm2/acm_receiver.h
+++ b/modules/audio_coding/main/acm2/acm_receiver.h
@@ -11,6 +11,7 @@
#ifndef WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_ACM_RECEIVER_H_
#define WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_ACM_RECEIVER_H_
+#include <map>
#include <vector>
#include "webrtc/base/scoped_ptr.h"
@@ -39,7 +40,7 @@
class AcmReceiver {
public:
struct Decoder {
- bool registered;
+ int acm_codec_id;
uint8_t payload_type;
// This field is meaningful for codecs where both mono and
// stereo versions are registered under the same ID.
@@ -334,7 +335,7 @@
bool nack_enabled_ GUARDED_BY(crit_sect_);
CallStatistics call_stats_ GUARDED_BY(crit_sect_);
NetEq* neteq_;
- Decoder decoders_[ACMCodecDB::kMaxNumCodecs];
+ std::map<int, Decoder> decoders_; // keyed by ACM codec ID
bool vad_enabled_;
Clock* clock_; // TODO(henrik.lundin) Make const if possible.
bool resampled_last_output_frame_ GUARDED_BY(crit_sect_);