Change ACM's CodecManager to hold one encoder instead of an array
With this change, the currently used encoder is held in a scoped_ptr.
iSAC is a special case, since the encoder instance is also a decoder
instance, so it may have to be available also if another send codec is
used. This is accomplished by having a separate scoped_ptr for iSAC.
Remove mirror ID from ACM codec database functions, and remove unused
functions from the database.
COAUTHOR=kwiberg@webrtc.org
BUG=4228
R=tina.legrand@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/48729004
Cr-Commit-Position: refs/heads/master@{#8982}
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_codec_database.cc b/webrtc/modules/audio_coding/main/acm2/acm_codec_database.cc
index 7710046..8a9a5de 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_codec_database.cc
+++ b/webrtc/modules/audio_coding/main/acm2/acm_codec_database.cc
@@ -227,7 +227,7 @@
// Gets the codec id number from the database. If there is some mismatch in
// the codec settings, the function will return an error code.
// NOTE! The first mismatch found will generate the return value.
-int ACMCodecDB::CodecNumber(const CodecInst& codec_inst, int* mirror_id) {
+int ACMCodecDB::CodecNumber(const CodecInst& codec_inst) {
// Look for a matching codec in the database.
int codec_id = CodecId(codec_inst);
@@ -243,13 +243,11 @@
// Comfort Noise is special case, packet-size & rate is not checked.
if (STR_CASE_CMP(database_[codec_id].plname, "CN") == 0) {
- *mirror_id = codec_id;
return codec_id;
}
// RED is special case, packet-size & rate is not checked.
if (STR_CASE_CMP(database_[codec_id].plname, "red") == 0) {
- *mirror_id = codec_id;
return codec_id;
}
@@ -278,16 +276,8 @@
// Check the validity of rate. Codecs with multiple rates have their own
// function for this.
- *mirror_id = codec_id;
if (STR_CASE_CMP("isac", codec_inst.plname) == 0) {
- if (IsISACRateValid(codec_inst.rate)) {
- // Set mirrorID to iSAC WB which is only created once to be used both for
- // iSAC WB and SWB, because they need to share struct.
- *mirror_id = kISAC;
- return codec_id;
- } else {
- return kInvalidRate;
- }
+ return IsISACRateValid(codec_inst.rate) ? codec_id : kInvalidRate;
} else if (STR_CASE_CMP("ilbc", codec_inst.plname) == 0) {
return IsILBCRateValid(codec_inst.rate, codec_inst.pacsize)
? codec_id : kInvalidRate;
@@ -350,22 +340,10 @@
// We didn't find a matching codec.
return -1;
}
-// Gets codec id number, and mirror id, from database for the receiver.
-int ACMCodecDB::ReceiverCodecNumber(const CodecInst& codec_inst,
- int* mirror_id) {
+// Gets codec id number from database for the receiver.
+int ACMCodecDB::ReceiverCodecNumber(const CodecInst& codec_inst) {
// Look for a matching codec in the database.
- int codec_id = CodecId(codec_inst);
-
- // Set |mirror_id| to |codec_id|, except for iSAC. In case of iSAC we always
- // set |mirror_id| to iSAC WB (kISAC) which is only created once to be used
- // both for iSAC WB and SWB, because they need to share struct.
- if (STR_CASE_CMP(codec_inst.plname, "ISAC") != 0) {
- *mirror_id = codec_id;
- } else {
- *mirror_id = kISAC;
- }
-
- return codec_id;
+ return CodecId(codec_inst);
}
// Returns the codec sampling frequency for codec with id = "codec_id" in
@@ -394,16 +372,6 @@
return neteq_decoders_;
}
-// Gets mirror id. The Id is used for codecs sharing struct for settings that
-// need different payload types.
-int ACMCodecDB::MirrorID(int codec_id) {
- if (STR_CASE_CMP(database_[codec_id].plname, "isac") == 0) {
- return kISAC;
- } else {
- return codec_id;
- }
-}
-
// Creates memory/instance for storing codec state.
ACMGenericCodec* ACMCodecDB::CreateCodecInstance(const CodecInst& codec_inst,
int cng_pt_nb,
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_codec_database.h b/webrtc/modules/audio_coding/main/acm2/acm_codec_database.h
index ea7eb23..adfe5c7 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_codec_database.h
+++ b/webrtc/modules/audio_coding/main/acm2/acm_codec_database.h
@@ -166,36 +166,17 @@
// 0 if successful, otherwise -1.
static int Codec(int codec_id, CodecInst* codec_inst);
- // Returns codec id and mirror id from database, given the information
- // received in the input [codec_inst]. Mirror id is a number that tells
- // where to find the codec's memory (instance). The number is either the
- // same as codec id (most common), or a number pointing at a different
- // entry in the database, if the codec has several entries with different
- // payload types. This is used for codecs that must share one struct even if
- // the payload type differs.
- // One example is the codec iSAC which has the same struct for both 16 and
- // 32 khz, but they have different entries in the database. Let's say the
- // function is called with iSAC 32kHz. The function will return 1 as that is
- // the entry in the data base, and [mirror_id] = 0, as that is the entry for
- // iSAC 16 kHz, which holds the shared memory.
+ // Returns codec id from database, given the information received in the input
+ // [codec_inst].
// Input:
// [codec_inst] - Information about the codec for which we require the
// database id.
- // Output:
- // [mirror_id] - mirror id, which most often is the same as the return
- // value, see above.
- // [err_message] - if present, in the event of a mismatch found between the
- // input and the database, a descriptive error message is
- // written here.
- // [err_message] - if present, the length of error message is returned here.
// Return:
// codec id if successful, otherwise < 0.
- static int CodecNumber(const CodecInst& codec_inst, int* mirror_id,
- char* err_message, int max_message_len_byte);
- static int CodecNumber(const CodecInst& codec_inst, int* mirror_id);
+ static int CodecNumber(const CodecInst& codec_inst);
static int CodecId(const CodecInst& codec_inst);
static int CodecId(const char* payload_name, int frequency, int channels);
- static int ReceiverCodecNumber(const CodecInst& codec_inst, int* mirror_id);
+ static int ReceiverCodecNumber(const CodecInst& codec_inst);
// Returns the codec sampling frequency for codec with id = "codec_id" in
// database.
@@ -221,19 +202,6 @@
// Returns the NetEQ decoder database.
static const NetEqDecoder* NetEQDecoders();
- // Returns mirror id, which is a number that tells where to find the codec's
- // memory (instance). It is either the same as codec id (most common), or a
- // number pointing at a different entry in the database, if the codec have
- // several entries with different payload types. This is used for codecs that
- // must share struct even if the payload type differs.
- // TODO(tlegrand): Check if function is needed, or if we can change
- // to access database directly.
- // Input:
- // [codec_id] - number that specifies codec's position in the database.
- // Return:
- // Mirror id on success, otherwise -1.
- static int MirrorID(int codec_id);
-
// Creates a codec wrapper containing an AudioEncoder object (or an
// ACMGenericCodec subclass during the refactoring time). The type of
// AudioEncoder is decided by looking at the information in |codec_inst|.
diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module.cc b/webrtc/modules/audio_coding/main/acm2/audio_coding_module.cc
index f1d7a5d..fa63491 100644
--- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module.cc
+++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module.cc
@@ -81,9 +81,7 @@
// Checks the validity of the parameters of the given codec
bool AudioCodingModule::IsCodecValid(const CodecInst& codec) {
- int mirror_id;
-
- int codec_number = acm2::ACMCodecDB::CodecNumber(codec, &mirror_id);
+ int codec_number = acm2::ACMCodecDB::CodecNumber(codec);
if (codec_number < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, -1,
diff --git a/webrtc/modules/audio_coding/main/acm2/codec_manager.cc b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc
index c3e340e..6e80be8 100644
--- a/webrtc/modules/audio_coding/main/acm2/codec_manager.cc
+++ b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc
@@ -34,9 +34,7 @@
}
// Check if the given codec is a valid to be registered as send codec.
-int IsValidSendCodec(const CodecInst& send_codec,
- bool is_primary_encoder,
- int* mirror_id) {
+int IsValidSendCodec(const CodecInst& send_codec, bool is_primary_encoder) {
int dummy_id = 0;
if ((send_codec.channels != 1) && (send_codec.channels != 2)) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
@@ -47,7 +45,7 @@
return -1;
}
- int codec_id = ACMCodecDB::CodecNumber(send_codec, mirror_id);
+ int codec_id = ACMCodecDB::CodecNumber(send_codec);
if (codec_id < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
"Invalid codec setting for the send codec.");
@@ -68,7 +66,6 @@
if (!STR_CASE_CMP(send_codec.plname, "telephone-event")) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
"telephone-event cannot be a send codec");
- *mirror_id = -1;
return -1;
}
@@ -77,7 +74,6 @@
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
"%d number of channels not supportedn for %s.",
send_codec.channels, send_codec.plname);
- *mirror_id = -1;
return -1;
}
@@ -87,20 +83,22 @@
if (IsCodecRED(&send_codec)) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
"RED cannot be secondary codec");
- *mirror_id = -1;
return -1;
}
if (IsCodecCN(&send_codec)) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
"DTX cannot be secondary codec");
- *mirror_id = -1;
return -1;
}
}
return codec_id;
}
+bool IsIsac(const CodecInst& codec) {
+ return !STR_CASE_CMP(codec.plname, "isac");
+}
+
const CodecInst kEmptyCodecInst = {-1, "noCodecRegistered", 0, 0, 0, 0};
} // namespace
@@ -119,11 +117,6 @@
send_codec_inst_(kEmptyCodecInst),
red_enabled_(false),
codec_fec_enabled_(false) {
- for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) {
- codecs_[i] = nullptr;
- mirror_codec_idx_[i] = -1;
- }
-
// Register the default payload type for RED and for CNG at sampling rates of
// 8, 16, 32 and 48 kHz.
for (int i = (ACMCodecDB::kNumCodecs - 1); i >= 0; i--) {
@@ -144,25 +137,11 @@
thread_checker_.DetachFromThread();
}
-CodecManager::~CodecManager() {
- for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) {
- if (codecs_[i] != NULL) {
- // Mirror index holds the address of the codec memory.
- assert(mirror_codec_idx_[i] > -1);
- if (codecs_[mirror_codec_idx_[i]] != NULL) {
- delete codecs_[mirror_codec_idx_[i]];
- codecs_[mirror_codec_idx_[i]] = NULL;
- }
-
- codecs_[i] = NULL;
- }
- }
-}
+CodecManager::~CodecManager() = default;
int CodecManager::RegisterSendCodec(const CodecInst& send_codec) {
DCHECK(thread_checker_.CalledOnValidThread());
- int mirror_id;
- int codec_id = IsValidSendCodec(send_codec, true, &mirror_id);
+ int codec_id = IsValidSendCodec(send_codec, true);
// Check for reported errors from function IsValidSendCodec().
if (codec_id < 0) {
@@ -243,36 +222,31 @@
// Check if the codec is already registered as send codec.
bool is_send_codec;
if (current_encoder_) {
- int send_codec_mirror_id;
- int send_codec_id =
- ACMCodecDB::CodecNumber(send_codec_inst_, &send_codec_mirror_id);
+ int send_codec_id = ACMCodecDB::CodecNumber(send_codec_inst_);
assert(send_codec_id >= 0);
- is_send_codec =
- (send_codec_id == codec_id) || (mirror_id == send_codec_mirror_id);
+ is_send_codec = send_codec_id == codec_id;
} else {
is_send_codec = false;
}
// If new codec, or new settings, register.
if (!is_send_codec) {
- if (!codecs_[mirror_id]) {
- codecs_[mirror_id] = ACMCodecDB::CreateCodecInstance(
+ ACMGenericCodec* new_codec;
+ if (!IsIsac(send_codec)) {
+ encoder_.reset(ACMCodecDB::CreateCodecInstance(
send_codec, cng_nb_pltype_, cng_wb_pltype_, cng_swb_pltype_,
- cng_fb_pltype_, red_enabled_, red_nb_pltype_);
- if (!codecs_[mirror_id]) {
- WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
- "Cannot Create the codec");
- return -1;
+ cng_fb_pltype_, red_enabled_, red_nb_pltype_));
+ new_codec = encoder_.get();
+ } else {
+ if (!isac_enc_dec_) {
+ isac_enc_dec_.reset(ACMCodecDB::CreateCodecInstance(
+ send_codec, cng_nb_pltype_, cng_wb_pltype_, cng_swb_pltype_,
+ cng_fb_pltype_, red_enabled_, red_nb_pltype_));
}
- mirror_codec_idx_[mirror_id] = mirror_id;
+ new_codec = isac_enc_dec_.get();
}
+ DCHECK(new_codec);
- if (mirror_id != codec_id) {
- codecs_[codec_id] = codecs_[mirror_id];
- mirror_codec_idx_[codec_id] = mirror_id;
- }
-
- ACMGenericCodec* codec_ptr = codecs_[codec_id];
WebRtcACMCodecParams codec_params;
memcpy(&(codec_params.codec_inst), &send_codec, sizeof(CodecInst));
@@ -280,7 +254,7 @@
codec_params.enable_dtx = dtx_enabled_;
codec_params.vad_mode = vad_mode_;
// Force initialization.
- if (codec_ptr->InitEncoder(&codec_params, true) < 0) {
+ if (new_codec->InitEncoder(&codec_params, true) < 0) {
// Could not initialize the encoder.
// Check if already have a registered codec.
@@ -306,18 +280,18 @@
// If we change codec we start fresh with RED.
// This is not strictly required by the standard.
- if (codec_ptr->SetCopyRed(red_enabled_) < 0) {
+ if (new_codec->SetCopyRed(red_enabled_) < 0) {
// We tried to preserve the old red status, if failed, it means the
// red status has to be flipped.
red_enabled_ = !red_enabled_;
}
- codec_ptr->SetVAD(&dtx_enabled_, &vad_enabled_, &vad_mode_);
+ new_codec->SetVAD(&dtx_enabled_, &vad_enabled_, &vad_mode_);
- if (!codec_ptr->HasInternalFEC()) {
+ if (!new_codec->HasInternalFEC()) {
codec_fec_enabled_ = false;
} else {
- if (codec_ptr->SetFEC(codec_fec_enabled_) < 0) {
+ if (new_codec->SetFEC(codec_fec_enabled_) < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
"Cannot set codec FEC");
return -1;
@@ -325,7 +299,7 @@
}
}
- current_encoder_ = codecs_[codec_id];
+ current_encoder_ = new_codec;
DCHECK(current_encoder_);
memcpy(&send_codec_inst_, &send_codec, sizeof(CodecInst));
return 0;
@@ -335,11 +309,6 @@
// If any parameter is valid then apply it and record.
bool force_init = false;
- if (mirror_id != codec_id) {
- codecs_[codec_id] = codecs_[mirror_id];
- mirror_codec_idx_[codec_id] = mirror_id;
- }
-
// Check the payload type.
if (send_codec.pltype != send_codec_inst_.pltype) {
// At this point check if the given payload type is valid.
@@ -396,7 +365,7 @@
// Check if a change in Rate is required.
if (send_codec.rate != send_codec_inst_.rate) {
- if (codecs_[codec_id]->SetBitRate(send_codec.rate) < 0) {
+ if (current_encoder_->SetBitRate(send_codec.rate) < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
"Could not change the codec rate.");
return -1;
@@ -404,10 +373,10 @@
send_codec_inst_.rate = send_codec.rate;
}
- if (!codecs_[codec_id]->HasInternalFEC()) {
+ if (!current_encoder_->HasInternalFEC()) {
codec_fec_enabled_ = false;
} else {
- if (codecs_[codec_id]->SetFEC(codec_fec_enabled_) < 0) {
+ if (current_encoder_->SetFEC(codec_fec_enabled_) < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id,
"Cannot set codec FEC");
return -1;
@@ -445,8 +414,7 @@
return -1;
}
- int mirror_id;
- int codec_id = ACMCodecDB::ReceiverCodecNumber(codec, &mirror_id);
+ int codec_id = ACMCodecDB::ReceiverCodecNumber(codec);
if (codec_id < 0 || codec_id >= ACMCodecDB::kNumCodecs) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
@@ -464,7 +432,7 @@
AudioDecoder* decoder = NULL;
// Get |decoder| associated with |codec|. |decoder| can be NULL if |codec|
// does not own its decoder.
- if (GetAudioDecoder(codec, codec_id, mirror_id, &decoder) < 0) {
+ if (GetAudioDecoder(codec, codec_id, &decoder) < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
"Wrong codec params to be registered as receive codec");
return -1;
@@ -554,57 +522,43 @@
}
void CodecManager::SetCngPayloadType(int sample_rate_hz, int payload_type) {
- for (auto* codec : codecs_) {
- if (codec) {
- codec->SetCngPt(sample_rate_hz, payload_type);
- }
- }
+ if (isac_enc_dec_)
+ isac_enc_dec_->SetCngPt(sample_rate_hz, payload_type);
+ if (encoder_)
+ encoder_->SetCngPt(sample_rate_hz, payload_type);
}
void CodecManager::SetRedPayloadType(int sample_rate_hz, int payload_type) {
- for (auto* codec : codecs_) {
- if (codec) {
- codec->SetRedPt(sample_rate_hz, payload_type);
- }
- }
+ if (isac_enc_dec_)
+ isac_enc_dec_->SetRedPt(sample_rate_hz, payload_type);
+ if (encoder_)
+ encoder_->SetRedPt(sample_rate_hz, payload_type);
}
int CodecManager::GetAudioDecoder(const CodecInst& codec,
int codec_id,
- int mirror_id,
AudioDecoder** decoder) {
- if (ACMCodecDB::OwnsDecoder(codec_id)) {
- // This codec has to own its own decoder. Therefore, it should create the
- // corresponding AudioDecoder class and insert it into NetEq. If the codec
- // does not exist create it.
- //
- // TODO(turajs): this part of the code is common with RegisterSendCodec(),
- // make a method for it.
- if (codecs_[mirror_id] == NULL) {
- codecs_[mirror_id] = ACMCodecDB::CreateCodecInstance(
- codec, cng_nb_pltype_, cng_wb_pltype_, cng_swb_pltype_,
- cng_fb_pltype_, red_enabled_, red_nb_pltype_);
- if (codecs_[mirror_id] == NULL) {
- WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
- "Cannot Create the codec");
- return -1;
- }
- mirror_codec_idx_[mirror_id] = mirror_id;
- }
-
- if (mirror_id != codec_id) {
- codecs_[codec_id] = codecs_[mirror_id];
- mirror_codec_idx_[codec_id] = mirror_id;
- }
- *decoder = codecs_[codec_id]->Decoder();
- if (!*decoder) {
- assert(false);
- return -1;
- }
- } else {
- *decoder = NULL;
+ if (!ACMCodecDB::OwnsDecoder(codec_id)) {
+ DCHECK(!IsIsac(codec)) << "Codec must not be iSAC at this point.";
+ *decoder = nullptr;
+ return 0;
}
-
+ DCHECK(IsIsac(codec)) << "Codec must be iSAC at this point.";
+ // This codec has to own its own decoder. Therefore, it should create the
+ // corresponding AudioDecoder class and insert it into NetEq. If the codec
+ // does not exist create it.
+ //
+ // TODO(turajs): this part of the code is common with RegisterSendCodec(),
+ // make a method for it.
+ if (!isac_enc_dec_) {
+ isac_enc_dec_.reset(ACMCodecDB::CreateCodecInstance(
+ codec, cng_nb_pltype_, cng_wb_pltype_, cng_swb_pltype_, cng_fb_pltype_,
+ red_enabled_, red_nb_pltype_));
+ if (!isac_enc_dec_)
+ return -1;
+ }
+ *decoder = isac_enc_dec_->Decoder();
+ DCHECK(*decoder);
return 0;
}
diff --git a/webrtc/modules/audio_coding/main/acm2/codec_manager.h b/webrtc/modules/audio_coding/main/acm2/codec_manager.h
index 8d5350d..3146467 100644
--- a/webrtc/modules/audio_coding/main/acm2/codec_manager.h
+++ b/webrtc/modules/audio_coding/main/acm2/codec_manager.h
@@ -72,7 +72,6 @@
// valid pointer, otherwise it will be NULL.
int GetAudioDecoder(const CodecInst& codec,
int codec_id,
- int mirror_id,
AudioDecoder** decoder);
AudioCodingModuleImpl* acm_;
@@ -90,8 +89,8 @@
CodecInst send_codec_inst_;
bool red_enabled_;
bool codec_fec_enabled_;
- ACMGenericCodec* codecs_[ACMCodecDB::kMaxNumCodecs];
- int mirror_codec_idx_[ACMCodecDB::kMaxNumCodecs];
+ rtc::scoped_ptr<ACMGenericCodec> isac_enc_dec_;
+ rtc::scoped_ptr<ACMGenericCodec> encoder_;
DISALLOW_COPY_AND_ASSIGN(CodecManager);
};