Opus mono/stereo on the same payloadtype, and fix of memory bug

During call setup Opus should always be signaled as a 48000 Hz stereo codec, not depending on what we plan to send, or how we plan to decode received packets.
The previous implementation had different payload types for mono and stereo, which breaks the proposed standard.

While working on this CL I ran in to the problem reported earlier, that we could get a crash related to deleting decoder memory. This should now be solved in Patch Set 3.

BUG=issue1013, issue1112

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3177 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
tina.legrand@webrtc.org
2012-11-28 12:23:29 +00:00
parent 81fb7bfd8b
commit c4590580e8
14 changed files with 161 additions and 60 deletions

View File

@ -190,10 +190,8 @@ const CodecInst ACMCodecDB::database_[] = {
#endif
#ifdef WEBRTC_CODEC_OPUS
// Opus internally supports 48, 24, 16, 12, 8 kHz.
// Mono
{120, "opus", 48000, 960, 1, 32000},
// Stereo
{121, "opus", 48000, 960, 2, 32000},
// Mono and stereo.
{120, "opus", 48000, 960, 2, 32000},
#endif
#ifdef WEBRTC_CODEC_SPEEX
{kDynamicPayloadtypes[count_database++], "speex", 8000, 160, 1, 11000},
@ -285,9 +283,7 @@ const ACMCodecDB::CodecSettings ACMCodecDB::codec_settings_[] = {
#ifdef WEBRTC_CODEC_OPUS
// Opus supports frames shorter than 10ms,
// but it doesn't help us to use them.
// Mono
{1, {960}, 0, 2},
// Stereo
// Mono and stereo.
{1, {960}, 0, 2},
#endif
#ifdef WEBRTC_CODEC_SPEEX
@ -375,10 +371,8 @@ const WebRtcNetEQDecoder ACMCodecDB::neteq_decoders_[] = {
kDecoderGSMFR,
#endif
#ifdef WEBRTC_CODEC_OPUS
// Mono
// Mono and stereo.
kDecoderOpus,
// Stereo
kDecoderOpus_2ch,
#endif
#ifdef WEBRTC_CODEC_SPEEX
kDecoderSPEEX_8,
@ -571,7 +565,13 @@ int ACMCodecDB::CodecId(const char* payload_name, int frequency, int channels) {
// always treated as true, like for RED.
name_match = (STR_CASE_CMP(database_[id].plname, payload_name) == 0);
frequency_match = (frequency == database_[id].plfreq) || (frequency == -1);
channels_match = (channels == database_[id].channels);
// The number of channels must match for all codecs but Opus.
if (STR_CASE_CMP(payload_name, "opus") != 0) {
channels_match = (channels == database_[id].channels);
} else {
// For opus we just check that number of channels is valid.
channels_match = (channels == 1 || channels == 2);
}
if (name_match && frequency_match && channels_match) {
// We have found a matching codec in the list.
@ -767,11 +767,7 @@ ACMGenericCodec* ACMCodecDB::CreateCodecInstance(const CodecInst* codec_inst) {
#endif
} else if (!STR_CASE_CMP(codec_inst->plname, "opus")) {
#ifdef WEBRTC_CODEC_OPUS
if (codec_inst->channels == 1) {
return new ACMOpus(kOpus);
} else {
return new ACMOpus(kOpus_2ch);
}
return new ACMOpus(kOpus);
#endif
} else if (!STR_CASE_CMP(codec_inst->plname, "speex")) {
#ifdef WEBRTC_CODEC_SPEEX

View File

@ -92,10 +92,8 @@ class ACMCodecDB {
, kGSMFR
#endif
#ifdef WEBRTC_CODEC_OPUS
// Mono
// Mono and stereo
, kOpus
// Stereo
, kOpus_2ch
#endif
#ifdef WEBRTC_CODEC_SPEEX
, kSPEEX8
@ -178,10 +176,8 @@ class ACMCodecDB {
enum {kSPEEX16 = -1};
#endif
#ifndef WEBRTC_CODEC_OPUS
// Mono
// Mono and stereo
enum {kOpus = -1};
// Stereo
enum {kOpus_2ch = -1};
#endif
#ifndef WEBRTC_CODEC_AVT
enum {kAVT = -1};

View File

@ -111,7 +111,7 @@ ACMOpus::ACMOpus(int16_t codecID)
// Opus has internal DTX, but we dont use it for now.
_hasInternalDTX = false;
if ((_codecID != ACMCodecDB::kOpus) && (_codecID != ACMCodecDB::kOpus_2ch)) {
if (_codecID != ACMCodecDB::kOpus) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, _uniqueID,
"Wrong codec id for Opus.");
_sampleFreq = -1;
@ -190,15 +190,17 @@ int16_t ACMOpus::InternalInitEncoder(WebRtcACMCodecParams* codecParams) {
}
int16_t ACMOpus::InternalInitDecoder(WebRtcACMCodecParams* codecParams) {
if (_decoderInstPtr != NULL) {
WebRtcOpus_DecoderFree(_decoderInstPtr);
_decoderInstPtr = NULL;
}
if (WebRtcOpus_DecoderCreate(&_decoderInstPtr,
codecParams->codecInstant.channels) < 0) {
return -1;
if(_decoderInstPtr == NULL) {
if (WebRtcOpus_DecoderCreate(&_decoderInstPtr,
codecParams->codecInstant.channels) < 0) {
return -1;
}
}
// Number of channels in decoder should match the number in |codecParams|.
assert(codecParams->codecInstant.channels ==
WebRtcOpus_DecoderChannels(_decoderInstPtr));
if (WebRtcOpus_DecoderInit(_decoderInstPtr) < 0) {
return -1;
}
@ -221,13 +223,8 @@ int32_t ACMOpus::CodecDef(WebRtcNetEQ_CodecDef& codecDef,
// TODO(tlegrand): Decoder is registered in NetEQ as a 32 kHz decoder, which
// is true until we have a full 48 kHz system, and remove the downsampling
// in the Opus decoder wrapper.
if (codecInst.channels == 1) {
SET_CODEC_PAR(codecDef, kDecoderOpus, codecInst.pltype, _decoderInstPtr,
32000);
} else {
SET_CODEC_PAR(codecDef, kDecoderOpus_2ch, codecInst.pltype,
_decoderInstPtr, 32000);
}
SET_CODEC_PAR(codecDef, kDecoderOpus, codecInst.pltype,
_decoderInstPtr, 32000);
// If this is the master of NetEQ, regular decoder will be added, otherwise
// the slave decoder will be used.

View File

@ -59,6 +59,10 @@ WebRtc_Word32 AudioCodingModule::Codec(const char* payload_name,
// Get default codec settings.
ACMCodecDB::Codec(codec_id, &codec);
// Keep the number of channels from the function call. For most codecs it
// will be the same value as in defaul codec settings, but not for all.
codec.channels = channels;
return 0;
}

View File

@ -1285,7 +1285,7 @@ WebRtc_Word32 AudioCodingModuleImpl::PlayoutFrequency() const {
return _netEq.CurrentSampFreqHz();
}
// Register possible reveive codecs, can be called multiple times,
// Register possible receive codecs, can be called multiple times,
// for codecs, CNG (NB, WB and SWB), DTMF, RED.
WebRtc_Word32 AudioCodingModuleImpl::RegisterReceiveCodec(
const CodecInst& receive_codec) {
@ -1394,14 +1394,30 @@ WebRtc_Word32 AudioCodingModuleImpl::RegisterReceiveCodec(
if (!_stereoReceive[codec_id]
&& (_lastRecvAudioCodecPlType == receive_codec.pltype)) {
// The last received payload type is the same as the current one, but
// was marked as mono. Reset to avoid problems.
// The last received payload type is the same as the one we are
// registering. Expected number of channels to receive is one (mono),
// but we are now registering the receiving codec as stereo (number of
// channels is 2).
// Set |_lastRecvAudioCodedPlType| to invalid value to trigger a flush in
// NetEq, and a reset of expected number of channels next time a packet is
// received in AudioCodingModuleImpl::IncomingPacket().
_lastRecvAudioCodecPlType = -1;
}
_stereoReceive[codec_id] = true;
_stereoReceiveRegistered = true;
} else {
if (_lastRecvAudioCodecPlType == receive_codec.pltype &&
_expected_channels == 2) {
// The last received payload type is the same as the one we are
// registering. Expected number of channels to receive is two (stereo),
// but we are now registering the receiving codec as mono (number of
// channels is 1).
// Set |_lastRecvAudioCodedPlType| to invalid value to trigger a flush in
// NetEq, and a reset of expected number of channels next time a packet is
// received in AudioCodingModuleImpl::IncomingPacket().
_lastRecvAudioCodecPlType = -1;
}
_stereoReceive[codec_id] = false;
}