Reset slave when switching to a stereo codec.

BUG=
TEST=

Review URL: https://webrtc-codereview.appspot.com/494003

git-svn-id: http://webrtc.googlecode.com/svn/trunk@2073 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
andrew@webrtc.org 2012-04-20 01:10:14 +00:00
parent 00a8dbb0ec
commit b61f1fa675
4 changed files with 279 additions and 253 deletions

View File

@ -59,48 +59,23 @@ _callbackCritSect(CriticalSectionWrapper::CreateCriticalSection())
} }
} }
ACMNetEQ::~ACMNetEQ() ACMNetEQ::~ACMNetEQ() {
{ {
{ CriticalSectionScoped lock(*_netEqCritSect);
CriticalSectionScoped lock(*_netEqCritSect); RemoveNetEQSafe(0); // Master.
for(WebRtc_Word16 idx = 0; idx < _numSlaves + 1; idx++) RemoveSlavesSafe();
{ }
if (_instMem[idx] != NULL) if (_netEqCritSect != NULL) {
{ delete _netEqCritSect;
free(_instMem[idx]); }
_instMem[idx] = NULL;
}
if (_netEqPacketBuffer[idx] != NULL)
{
free(_netEqPacketBuffer[idx]);
_netEqPacketBuffer[idx] = NULL;
}
if(_ptrVADInst[idx] != NULL)
{
WebRtcVad_Free(_ptrVADInst[idx]);
_ptrVADInst[idx] = NULL;
}
}
if(_masterSlaveInfo != NULL)
{
free(_masterSlaveInfo);
_masterSlaveInfo = NULL;
}
}
if(_netEqCritSect != NULL)
{
delete _netEqCritSect;
}
if(_decodeLock != NULL) if (_decodeLock != NULL) {
{ delete _decodeLock;
delete _decodeLock; }
}
if(_callbackCritSect != NULL) if (_callbackCritSect != NULL) {
{ delete _callbackCritSect;
delete _callbackCritSect; }
}
} }
WebRtc_Word32 WebRtc_Word32
@ -1146,6 +1121,38 @@ ACMNetEQ::PlayoutTimestamp(
} }
} }
void ACMNetEQ::RemoveSlaves() {
CriticalSectionScoped lock(*_netEqCritSect);
RemoveSlavesSafe();
}
void ACMNetEQ::RemoveSlavesSafe() {
for (int i = 1; i < _numSlaves + 1; i++) {
RemoveNetEQSafe(i);
}
if (_masterSlaveInfo != NULL) {
free(_masterSlaveInfo);
_masterSlaveInfo = NULL;
}
_numSlaves = 0;
}
void ACMNetEQ::RemoveNetEQSafe(int index) {
if (_instMem[index] != NULL) {
free(_instMem[index]);
_instMem[index] = NULL;
}
if (_netEqPacketBuffer[index] != NULL) {
free(_netEqPacketBuffer[index]);
_netEqPacketBuffer[index] = NULL;
}
if (_ptrVADInst[index] != NULL) {
WebRtcVad_Free(_ptrVADInst[index]);
_ptrVADInst[index] = NULL;
}
}
WebRtc_Word16 WebRtc_Word16
ACMNetEQ::AddSlave( ACMNetEQ::AddSlave(
const WebRtcNetEQDecoder* usedCodecs, const WebRtcNetEQDecoder* usedCodecs,

View File

@ -305,6 +305,9 @@ public:
enum JB {masterJB = 0, slaveJB = 1}; enum JB {masterJB = 0, slaveJB = 1};
// Delete all slaves.
void RemoveSlaves();
WebRtc_Word16 AddSlave( WebRtc_Word16 AddSlave(
const WebRtcNetEQDecoder* usedCodecs, const WebRtcNetEQDecoder* usedCodecs,
WebRtc_Word16 noOfCodecs); WebRtc_Word16 noOfCodecs);
@ -352,6 +355,11 @@ private:
WebRtc_Word16 noOfCodecs, WebRtc_Word16 noOfCodecs,
const WebRtc_Word16 idx); const WebRtc_Word16 idx);
// Delete the NetEQ corresponding to |index|.
void RemoveNetEQSafe(int index);
void RemoveSlavesSafe();
void* _inst[MAX_NUM_SLAVE_NETEQ + 1]; void* _inst[MAX_NUM_SLAVE_NETEQ + 1];
void* _instMem[MAX_NUM_SLAVE_NETEQ + 1]; void* _instMem[MAX_NUM_SLAVE_NETEQ + 1];

View File

@ -59,7 +59,6 @@ AudioCodingModuleImpl::AudioCodingModuleImpl(
_cng_wb_pltype(255), _cng_wb_pltype(255),
_cng_swb_pltype(255), _cng_swb_pltype(255),
_red_pltype(255), _red_pltype(255),
_cng_reg_receiver(false),
_vadEnabled(false), _vadEnabled(false),
_dtxEnabled(false), _dtxEnabled(false),
_vadMode(VADNormal), _vadMode(VADNormal),
@ -120,11 +119,11 @@ AudioCodingModuleImpl::AudioCodingModuleImpl(
// CNG for the three frequencies 8, 16 and 32 kHz // CNG for the three frequencies 8, 16 and 32 kHz
for (int i = (ACMCodecDB::kNumCodecs - 1); i>=0; i--) for (int i = (ACMCodecDB::kNumCodecs - 1); i>=0; i--)
{ {
if((STR_CASE_CMP(ACMCodecDB::database_[i].plname, "red") == 0)) if (IsCodecRED(i))
{ {
_red_pltype = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype); _red_pltype = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
} }
else if ((STR_CASE_CMP(ACMCodecDB::database_[i].plname, "CN") == 0)) else if (IsCodecCN(i))
{ {
if (ACMCodecDB::database_[i].plfreq == 8000) if (ACMCodecDB::database_[i].plfreq == 8000)
{ {
@ -686,7 +685,7 @@ mono codecs are supported, i.e. channels=1.", sendCodec.channels);
// RED can be registered with other payload type. If not registered a default // RED can be registered with other payload type. If not registered a default
// payload type is used. // payload type is used.
if(!STR_CASE_CMP(sendCodec.plname, "red")) if (IsCodecRED(sendCodec))
{ {
// TODO(tlegrand): Remove this check. Already taken care of in // TODO(tlegrand): Remove this check. Already taken care of in
// ACMCodecDB::CodecNumber(). // ACMCodecDB::CodecNumber().
@ -705,7 +704,7 @@ mono codecs are supported, i.e. channels=1.", sendCodec.channels);
// CNG can be registered with other payload type. If not registered the // CNG can be registered with other payload type. If not registered the
// default payload types from codec database will be used. // default payload types from codec database will be used.
if(!STR_CASE_CMP(sendCodec.plname, "CN")) if (IsCodecCN(sendCodec))
{ {
// CNG is registered // CNG is registered
switch(sendCodec.plfreq) switch(sendCodec.plfreq)
@ -1362,65 +1361,48 @@ AudioCodingModuleImpl::InitializeReceiver()
return InitializeReceiverSafe(); return InitializeReceiverSafe();
} }
// Initialize receiver, resets codec database etc // Initialize receiver, resets codec database etc.
WebRtc_Word32 WebRtc_Word32 AudioCodingModuleImpl::InitializeReceiverSafe() {
AudioCodingModuleImpl::InitializeReceiverSafe() // If the receiver is already initialized then we want to destroy any
{ // existing decoders. After a call to this function, we should have a clean
// If the receiver is already initialized then we // start-up.
// also like to destruct decoders if any exist. After a call if (_receiverInitialized) {
// to this function, we should have a clean start-up. for (int i = 0; i < ACMCodecDB::kNumCodecs; i++) {
if(_receiverInitialized) if (UnregisterReceiveCodecSafe(i) < 0) {
{
for(int codecCntr = 0; codecCntr < ACMCodecDB::kNumCodecs; codecCntr++)
{
if(UnregisterReceiveCodecSafe(codecCntr) < 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id,
"InitializeReceiver() failed, Could not unregister codec");
return -1;
}
}
}
if (_netEq.Init() != 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id,
"InitializeReceiver() failed, Could not initialize NetEQ"); "InitializeReceiver() failed, Could not unregister codec");
return -1; return -1;
}
} }
_netEq.SetUniqueId(_id); }
if (_netEq.AllocatePacketBuffer(ACMCodecDB::NetEQDecoders(), if (_netEq.Init() != 0) {
ACMCodecDB::kNumCodecs) != 0) WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id,
{ "InitializeReceiver() failed, Could not initialize NetEQ");
return -1;
}
_netEq.SetUniqueId(_id);
if (_netEq.AllocatePacketBuffer(ACMCodecDB::NetEQDecoders(),
ACMCodecDB::kNumCodecs) != 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id,
"NetEQ cannot allocatePacket Buffer");
return -1;
}
// Register RED and CN
for (int i = 0; i < ACMCodecDB::kNumCodecs; i++) {
if (IsCodecRED(i) || IsCodecCN(i)) {
if (RegisterRecCodecMSSafe(ACMCodecDB::database_[i], i, i,
ACMNetEQ::masterJB) < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id,
"NetEQ cannot allocatePacket Buffer"); "Cannot register master codec.");
return -1; return -1;
}
_registeredPlTypes[i] = ACMCodecDB::database_[i].pltype;
} }
}
// Register RED and CN _receiverInitialized = true;
int regInNeteq = 0; return 0;
for (int i = (ACMCodecDB::kNumCodecs - 1); i>-1; i--) {
if((STR_CASE_CMP(ACMCodecDB::database_[i].plname, "red") == 0)) {
regInNeteq = 1;
} else if ((STR_CASE_CMP(ACMCodecDB::database_[i].plname, "CN") == 0)) {
regInNeteq = 1;
}
if (regInNeteq == 1) {
if(RegisterRecCodecMSSafe(ACMCodecDB::database_[i], i, i,
ACMNetEQ::masterJB) < 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id,
"Cannot register master codec.");
return -1;
}
_registeredPlTypes[i] = ACMCodecDB::database_[i].pltype;
regInNeteq = 0;
}
}
_cng_reg_receiver = true;
_receiverInitialized = true;
return 0;
} }
// Reset the decoder state // Reset the decoder state
@ -1522,129 +1504,92 @@ AudioCodingModuleImpl::RegisterReceiveCodec(
// If codec already registered, unregister. Except for CN where we only // If codec already registered, unregister. Except for CN where we only
// unregister if payload type is changing. // unregister if payload type is changing.
if ((_registeredPlTypes[codecId] == receiveCodec.pltype) && if ((_registeredPlTypes[codecId] == receiveCodec.pltype) &&
(STR_CASE_CMP(receiveCodec.plname, "CN") == 0)) { IsCodecCN(receiveCodec)) {
// Codec already registered as receiver with this payload type. Nothing // Codec already registered as receiver with this payload type. Nothing
// to be done. // to be done.
return 0; return 0;
} else if (_registeredPlTypes[codecId] != -1) { } else if (_registeredPlTypes[codecId] != -1) {
if(UnregisterReceiveCodecSafe(codecId) < 0) { if (UnregisterReceiveCodecSafe(codecId) < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id,
"Cannot register master codec.");
return -1;
}
}
if(RegisterRecCodecMSSafe(receiveCodec, codecId, mirrorId,
ACMNetEQ::masterJB) < 0)
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id, WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id,
"Cannot register master codec."); "Cannot register master codec.");
return -1; return -1;
}
} }
// If CN is being registered in master, and we have at least one stereo if (RegisterRecCodecMSSafe(receiveCodec, codecId, mirrorId,
// codec registered in receiver, register CN in slave. ACMNetEQ::masterJB) < 0) {
if (STR_CASE_CMP(receiveCodec.plname, "CN") == 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id,
_cng_reg_receiver = true; "Cannot register master codec.");
if (_stereoReceiveRegistered) { return -1;
// At least one of the registered receivers is stereo, so go
// a head and add CN to the slave.
if(RegisterRecCodecMSSafe(receiveCodec, codecId, mirrorId,
ACMNetEQ::slaveJB) < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding,
_id, "Cannot register slave codec.");
return -1;
}
_stereoReceive[codecId] = true;
_registeredPlTypes[codecId] = receiveCodec.pltype;
return 0;
}
} }
// If receive stereo, make sure we have two instances of NetEQ, one for each // TODO(andrew): Refactor how the slave is initialized. Can we instead
// channel. Mark CN and RED as stereo. // always start up a slave and pre-register CN and RED? We should be able
if(receiveCodec.channels == 2) // to get rid of _stereoReceiveRegistered.
{ // http://code.google.com/p/webrtc/issues/detail?id=453
if(_netEq.NumSlaves() < 1)
{ // Register stereo codecs with the slave, or, if we've had already seen a
if(_netEq.AddSlave(ACMCodecDB::NetEQDecoders(), // stereo codec, register CN or RED as a special case.
ACMCodecDB::kNumCodecs) < 0) if (receiveCodec.channels == 2 || (_stereoReceiveRegistered &&
{ (IsCodecCN(receiveCodec) || IsCodecRED(receiveCodec)))) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, // TODO(andrew): refactor this block to combine with InitStereoSlave().
_id, "Cannot Add Slave jitter buffer to NetEQ.");
return -1; if (!_stereoReceiveRegistered) {
// This is the first time a stereo codec has been registered. Make
// some stereo preparations.
// Add a stereo slave.
assert(_netEq.NumSlaves() == 0);
if (_netEq.AddSlave(ACMCodecDB::NetEQDecoders(),
ACMCodecDB::kNumCodecs) < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id,
"Cannot add slave jitter buffer to NetEQ.");
return -1;
}
// Register any existing CN or RED codecs with the slave and as stereo.
for (int i = 0; i < ACMCodecDB::kNumCodecs; i++) {
if (_registeredPlTypes[i] != -1 &&
(IsCodecRED(i) || IsCodecCN(i))) {
_stereoReceive[i] = true;
CodecInst codec;
memcpy(&codec, &ACMCodecDB::database_[i], sizeof(CodecInst));
codec.pltype = _registeredPlTypes[i];
if (RegisterRecCodecMSSafe(codec, i, i, ACMNetEQ::slaveJB) < 0) {
WEBRTC_TRACE(kTraceError, kTraceAudioCoding, _id,
"Cannot register slave codec.");
return -1;
} }
}
} }
}
// If this is the first time a stereo codec is registered, RED and CN if (RegisterRecCodecMSSafe(receiveCodec, codecId, mirrorId,
// should be register in slave, if they are registered in master. ACMNetEQ::slaveJB) < 0) {
if (!_stereoReceiveRegistered) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id,
bool reg_in_neteq = false; "Cannot register slave codec.");
for (int i = (ACMCodecDB::kNumCodecs - 1); i > -1; i--) { return -1;
if (STR_CASE_CMP(ACMCodecDB::database_[i].plname, "RED") == 0) { }
if (_registeredPlTypes[i] != -1) {
// Mark RED as stereo, since we have registered at least
// one stereo receive codec.
_stereoReceive[i] = true;
reg_in_neteq = true;
}
} else if (STR_CASE_CMP(ACMCodecDB::database_[i].plname, "CN")
== 0) {
if (_cng_reg_receiver) {
// Mark CN as stereo, since we have registered at least
// one stereo receive codec.
_stereoReceive[i] = true;
reg_in_neteq = true;
}
}
if (reg_in_neteq) { if (!_stereoReceive[codecId] &&
CodecInst tmp_codec; (_lastRecvAudioCodecPlType == receiveCodec.pltype)) {
memcpy(&tmp_codec, &ACMCodecDB::database_[i], // The last received payload type is the same as the current one, but
sizeof(CodecInst)); // was marked as mono. Reset to avoid problems.
tmp_codec.pltype = _registeredPlTypes[i]; _lastRecvAudioCodecPlType = -1;
// Register RED of CN in slave, with the same payload type }
// as in master.
if(RegisterRecCodecMSSafe(tmp_codec, i, i,
ACMNetEQ::slaveJB) < 0) {
WEBRTC_TRACE(webrtc::kTraceError,
webrtc::kTraceAudioCoding, _id,
"Cannot register slave codec.");
return -1;
}
reg_in_neteq = false;
}
}
}
if(RegisterRecCodecMSSafe(receiveCodec, codecId, mirrorId, _stereoReceive[codecId] = true;
ACMNetEQ::slaveJB) < 0) _stereoReceiveRegistered = true;
{
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id,
"Cannot register slave codec.");
return -1;
}
// Last received payload type equal the current one, but was marked
// as mono. Reset to avoid problems.
if((_stereoReceive[codecId] == false) &&
(_lastRecvAudioCodecPlType == receiveCodec.pltype))
{
_lastRecvAudioCodecPlType = -1;
}
_stereoReceive[codecId] = true;
_stereoReceiveRegistered = true;
} }
else else {
{ _stereoReceive[codecId] = false;
_stereoReceive[codecId] = false;
} }
_registeredPlTypes[codecId] = receiveCodec.pltype; _registeredPlTypes[codecId] = receiveCodec.pltype;
if(!STR_CASE_CMP(receiveCodec.plname, "RED")) if (IsCodecRED(receiveCodec)) {
{ _receiveREDPayloadType = receiveCodec.pltype;
_receiveREDPayloadType = receiveCodec.pltype;
} }
return 0; return 0;
} }
@ -1738,7 +1683,7 @@ AudioCodingModuleImpl::RegisterRecCodecMSSafe(
return -1; return -1;
} }
// Guaranty that the same payload-type that is // Guarantee that the same payload-type that is
// registered in NetEQ is stored in the codec. // registered in NetEQ is stored in the codec.
codecArray[codecId]->SaveDecoderParam(&codecParams); codecArray[codecId]->SaveDecoderParam(&codecParams);
} }
@ -1840,38 +1785,8 @@ AudioCodingModuleImpl::IncomingPacket(
{ {
if(_registeredPlTypes[i] == myPayloadType) if(_registeredPlTypes[i] == myPayloadType)
{ {
if(_codecs[i] == NULL) if (UpdateUponReceivingCodec(i) != 0)
{ return -1;
// we found a payload type but the corresponding
// codec is NULL this should not happen
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id,
"IncomingPacket() Error, payload type found but corresponding "
"codec is NULL");
return -1;
}
_codecs[i]->UpdateDecoderSampFreq(i);
_netEq.SetReceivedStereo(_stereoReceive[i]);
_current_receive_codec_idx = i;
// If we have a change in expected number of channels,
// flush packet buffers in NetEQ.
if ((_stereoReceive[i] && (_expected_channels == 1)) ||
(!_stereoReceive[i] && (_expected_channels == 2))) {
_netEq.FlushBuffers();
_codecs[i]->ResetDecoder(myPayloadType);
}
// Store number of channels we expect to receive for the
// current payload type.
if (_stereoReceive[i]) {
_expected_channels = 2;
} else {
_expected_channels = 1;
}
// Reset previous received channel
_prev_received_channel = 0;
break; break;
} }
} }
@ -1897,6 +1812,91 @@ AudioCodingModuleImpl::IncomingPacket(
} }
} }
int AudioCodingModuleImpl::UpdateUponReceivingCodec(int index) {
if (_codecs[index] == NULL) {
WEBRTC_TRACE(kTraceError, kTraceAudioCoding, _id,
"IncomingPacket() error: payload type found but corresponding codec "
"is NULL");
return -1;
}
_codecs[index]->UpdateDecoderSampFreq(index);
_netEq.SetReceivedStereo(_stereoReceive[index]);
_current_receive_codec_idx = index;
// If we have a change in the expected number of channels, flush packet
// buffers in NetEQ.
if ((_stereoReceive[index] && (_expected_channels == 1)) ||
(!_stereoReceive[index] && (_expected_channels == 2))) {
_netEq.FlushBuffers();
_codecs[index]->ResetDecoder(_registeredPlTypes[index]);
}
if (_stereoReceive[index] && (_expected_channels == 1)) {
// When switching from a mono to stereo codec reset the slave.
if (InitStereoSlave() != 0)
return -1;
}
// Store number of channels we expect to receive for the current payload type.
if (_stereoReceive[index]) {
_expected_channels = 2;
} else {
_expected_channels = 1;
}
// Reset previous received channel
_prev_received_channel = 0;
return 0;
}
bool AudioCodingModuleImpl::IsCodecForSlave(int index) {
return (_registeredPlTypes[index] != -1 && _stereoReceive[index]);
}
bool AudioCodingModuleImpl::IsCodecRED(int index) {
return (IsCodecRED(ACMCodecDB::database_[index]));
}
bool AudioCodingModuleImpl::IsCodecRED(CodecInst codec) {
return (STR_CASE_CMP(codec.plname, "RED") == 0);
}
bool AudioCodingModuleImpl::IsCodecCN(int index) {
return (IsCodecCN(ACMCodecDB::database_[index]));
}
bool AudioCodingModuleImpl::IsCodecCN(CodecInst codec) {
return (STR_CASE_CMP(codec.plname, "CN") == 0);
}
int AudioCodingModuleImpl::InitStereoSlave() {
_netEq.RemoveSlaves();
if (_netEq.AddSlave(ACMCodecDB::NetEQDecoders(),
ACMCodecDB::kNumCodecs) < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _id,
"Cannot add slave jitter buffer to NetEQ.");
return -1;
}
// Register all needed codecs with slave.
for (int i = 0; i < ACMCodecDB::kNumCodecs; i++) {
if (_codecs[i] != NULL && IsCodecForSlave(i)) {
WebRtcACMCodecParams decoder_params;
if (_codecs[i]->DecoderParams(&decoder_params, _registeredPlTypes[i])) {
if (RegisterRecCodecMSSafe(decoder_params.codecInstant,
i, ACMCodecDB::MirrorID(i),
ACMNetEQ::slaveJB) < 0) {
WEBRTC_TRACE(kTraceError, kTraceAudioCoding, _id,
"Cannot register slave codec.");
return -1;
}
}
}
}
return 0;
}
// Minimum playout delay (Used for lip-sync) // Minimum playout delay (Used for lip-sync)
WebRtc_Word32 WebRtc_Word32
AudioCodingModuleImpl::SetMinimumPlayoutDelay( AudioCodingModuleImpl::SetMinimumPlayoutDelay(
@ -2639,26 +2639,15 @@ AudioCodingModuleImpl::UnregisterReceiveCodecSafe(
} }
// CN is a special case for NetEQ, all three sampling frequencies // CN is a special case for NetEQ, all three sampling frequencies
// are unregistered if one is deleted // are unregistered if one is deleted.
if(STR_CASE_CMP(ACMCodecDB::database_[codecID].plname, "CN") == 0) if (IsCodecCN(codecID)) {
{ for (int i = 0; i < ACMCodecDB::kNumCodecs; i++) {
// Search codecs nearby in the database to unregister all CN. if (IsCodecCN(i)) {
// TODO(tlegrand): do this search in a safe way. We can search _stereoReceive[i] = false;
// outside the database. _registeredPlTypes[i] = -1;
for (int i=-2; i<3; i++)
{
if (STR_CASE_CMP(ACMCodecDB::database_[codecID+i].plname, "CN") == 0)
{
if(_stereoReceive[codecID+i])
{
_stereoReceive[codecID+i] = false;
}
_registeredPlTypes[codecID+i] = -1;
}
} }
_cng_reg_receiver = false; }
} else } else {
{
if(codecID == mirrorID) if(codecID == mirrorID)
{ {
_codecs[codecID]->DestructDecoder(); _codecs[codecID]->DestructDecoder();
@ -2679,12 +2668,13 @@ AudioCodingModuleImpl::UnregisterReceiveCodecSafe(
if (_stereoReceive[i]) { if (_stereoReceive[i]) {
// We still have stereo codecs registered. // We still have stereo codecs registered.
no_stereo = false; no_stereo = false;
break; break;
} }
} }
// If we don't have any stereo codecs left, change status. // If we don't have any stereo codecs left, change status.
if (no_stereo) { if (no_stereo) {
_netEq.RemoveSlaves(); // No longer need the slave.
_stereoReceiveRegistered = false; _stereoReceiveRegistered = false;
} }
} }

View File

@ -306,6 +306,28 @@ protected:
ACMNetEQ::JB jitterBuffer); ACMNetEQ::JB jitterBuffer);
private: private:
// Change required states after starting to receive the codec corresponding
// to |index|.
int UpdateUponReceivingCodec(int index);
// Remove all slaves and initialize a stereo slave with required codecs
// from the master.
int InitStereoSlave();
// Returns true if the codec's |index| is registered with the master and
// is a stereo codec, RED or CN.
bool IsCodecForSlave(int index);
// Returns true if the |codec| is RED.
bool IsCodecRED(CodecInst codec);
// ...or if its |index| is RED.
bool IsCodecRED(int index);
// Returns true if the |codec| is CN.
bool IsCodecCN(int index);
// ...or if its |index| is CN.
bool IsCodecCN(CodecInst codec);
AudioPacketizationCallback* _packetizationCallback; AudioPacketizationCallback* _packetizationCallback;
WebRtc_Word32 _id; WebRtc_Word32 _id;
WebRtc_UWord32 _lastTimestamp; WebRtc_UWord32 _lastTimestamp;
@ -315,7 +337,6 @@ private:
uint8_t _cng_wb_pltype; uint8_t _cng_wb_pltype;
uint8_t _cng_swb_pltype; uint8_t _cng_swb_pltype;
uint8_t _red_pltype; uint8_t _red_pltype;
bool _cng_reg_receiver;
bool _vadEnabled; bool _vadEnabled;
bool _dtxEnabled; bool _dtxEnabled;
ACMVADMode _vadMode; ACMVADMode _vadMode;