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:
parent
00a8dbb0ec
commit
b61f1fa675
@ -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,
|
||||||
|
@ -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];
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user