Reset audio bufer if codec changes, b/10835525.

If there is audio in a codec's audio buffer and sample-rate or number of channels change the audio buffer has to reset. Otherwise, the amount of audio in the buffer is misinterpreted any syncronization between 10ms audio blocks and their associated timestamps is lost.

For instance, assume changing from stereo to mono when there is 10ms stereo in the buffer. The "new" codec will interpret this as 20 ms audio, therefore, 2 blocks of 10 ms, but there is only one timestamp. This will results in  ACMGenericCodec::in_timestamp_ix_write_ updated to a negative number after an encode is performed.

The drawback with this solution is that if packet-size of the codec is changed then audio buffer is reset wich is not necessary. We accept this as it is a rare case in practice that clients of ACM re-register send codecs to change packet-size.

R=andrew@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4887 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
turaj@webrtc.org
2013-10-01 01:17:37 +00:00
parent 8e2f9bce71
commit 522227012d
2 changed files with 29 additions and 20 deletions

View File

@ -123,7 +123,10 @@ int32_t ACMGenericCodec::Add10MsDataSafe(const uint32_t timestamp,
if ((in_audio_ix_write_ >= length_smpl * audio_channel) &&
(in_timestamp_ix_write_ > 0)) {
in_audio_ix_write_ -= length_smpl * audio_channel;
assert(in_timestamp_ix_write_ >= 0);
in_timestamp_ix_write_--;
assert(in_audio_ix_write_ >= 0);
WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceAudioCoding, unique_id_,
"Adding 10ms with previous timestamp, overwriting the "
"previous 10ms");
@ -160,8 +163,11 @@ int32_t ACMGenericCodec::Add10MsDataSafe(const uint32_t timestamp,
memmove(in_timestamp_, in_timestamp_ + missed_10ms_blocks,
(in_timestamp_ix_write_ - missed_10ms_blocks) * sizeof(uint32_t));
in_timestamp_ix_write_ -= missed_10ms_blocks;
assert(in_timestamp_ix_write_ >= 0);
in_timestamp_[in_timestamp_ix_write_] = timestamp;
in_timestamp_ix_write_++;
assert(in_timestamp_ix_write_ < TIMESTAMP_BUFFER_SIZE_W32);
// Buffer is full.
in_audio_ix_write_ = AUDIO_BUFFER_SIZE_W16;
@ -173,12 +179,11 @@ int32_t ACMGenericCodec::Add10MsDataSafe(const uint32_t timestamp,
memcpy(in_audio_ + in_audio_ix_write_, data,
length_smpl * audio_channel * sizeof(int16_t));
in_audio_ix_write_ += length_smpl * audio_channel;
assert(in_timestamp_ix_write_ < TIMESTAMP_BUFFER_SIZE_W32);
assert(in_timestamp_ix_write_ >= 0);
in_timestamp_[in_timestamp_ix_write_] = timestamp;
in_timestamp_ix_write_++;
assert(in_timestamp_ix_write_ < TIMESTAMP_BUFFER_SIZE_W32);
return 0;
}
@ -345,6 +350,7 @@ int16_t ACMGenericCodec::Encode(uint8_t* bitstream,
(in_timestamp_ix_write_ - num_10ms_blocks) * sizeof(int32_t));
}
in_timestamp_ix_write_ -= num_10ms_blocks;
assert(in_timestamp_ix_write_ >= 0);
// Remove encoded audio and move next audio to be encoded to the beginning
// of the buffer. Accordingly, adjust the read and write indices.
@ -448,11 +454,8 @@ int16_t ACMGenericCodec::InitEncoderSafe(WebRtcACMCodecParams* codec_params,
int mirrorID;
int codec_number = ACMCodecDB::CodecNumber(codec_params->codec_inst,
&mirrorID);
if (codec_number < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
"InitEncoderSafe: error, codec number negative");
return -1;
}
assert(codec_number >= 0);
// Check if the parameters are for this codec.
if ((codec_id_ >= 0) && (codec_id_ != codec_number) &&
(codec_id_ != mirrorID)) {
@ -481,7 +484,7 @@ int16_t ACMGenericCodec::InitEncoderSafe(WebRtcACMCodecParams* codec_params,
encoder_exist_ = true;
}
}
frame_len_smpl_ = (codec_params->codec_inst).pacsize;
frame_len_smpl_ = codec_params->codec_inst.pacsize;
num_channels_ = codec_params->codec_inst.channels;
status = InternalInitEncoder(codec_params);
if (status < 0) {
@ -490,24 +493,25 @@ int16_t ACMGenericCodec::InitEncoderSafe(WebRtcACMCodecParams* codec_params,
encoder_initialized_ = false;
return -1;
} else {
// TODO(turajs): Move these allocations to the constructor issue 2445.
// Store encoder parameters.
memcpy(&encoder_params_, codec_params, sizeof(WebRtcACMCodecParams));
encoder_initialized_ = true;
if (in_audio_ == NULL) {
in_audio_ = new int16_t[AUDIO_BUFFER_SIZE_W16];
if (in_audio_ == NULL) {
return -1;
}
memset(in_audio_, 0, AUDIO_BUFFER_SIZE_W16 * sizeof(int16_t));
}
if (in_timestamp_ == NULL) {
in_timestamp_ = new uint32_t[TIMESTAMP_BUFFER_SIZE_W32];
if (in_timestamp_ == NULL) {
return -1;
}
memset(in_timestamp_, 0, sizeof(uint32_t) * TIMESTAMP_BUFFER_SIZE_W32);
}
}
// Fresh start of audio buffer.
memset(in_audio_, 0, sizeof(*in_audio_) * AUDIO_BUFFER_SIZE_W16);
memset(in_timestamp_, 0, sizeof(*in_timestamp_) * TIMESTAMP_BUFFER_SIZE_W32);
in_audio_ix_write_ = 0;
in_audio_ix_read_ = 0;
in_timestamp_ix_write_ = 0;
return SetVADSafe(&codec_params->enable_dtx, &codec_params->enable_vad,
&codec_params->vad_mode);
}

View File

@ -170,6 +170,7 @@ int32_t ACMGenericCodec::Add10MsDataSafe(const uint32_t timestamp,
memmove(in_timestamp_, in_timestamp_ + missed_10ms_blocks,
(in_timestamp_ix_write_ - missed_10ms_blocks) * sizeof(uint32_t));
in_timestamp_ix_write_ -= missed_10ms_blocks;
assert(in_timestamp_ix_write_ >= 0);
in_timestamp_[in_timestamp_ix_write_] = timestamp;
in_timestamp_ix_write_++;
@ -351,7 +352,7 @@ int16_t ACMGenericCodec::Encode(uint8_t* bitstream,
(in_timestamp_ix_write_ - num_10ms_blocks) * sizeof(int32_t));
}
in_timestamp_ix_write_ -= num_10ms_blocks;
assert(in_timestamp_ix_write_ >= 0);
// Remove encoded audio and move next audio to be encoded to the beginning
// of the buffer. Accordingly, adjust the read and write indices.
if (in_audio_ix_read_ < in_audio_ix_write_) {
@ -359,6 +360,7 @@ int16_t ACMGenericCodec::Encode(uint8_t* bitstream,
(in_audio_ix_write_ - in_audio_ix_read_) * sizeof(int16_t));
}
in_audio_ix_write_ -= in_audio_ix_read_;
assert(in_timestamp_ix_write_ >= 0);
in_audio_ix_read_ = 0;
last_encoded_timestamp_ = *timestamp;
return (status < 0) ? (-1) : (*bitstream_len_byte);
@ -574,20 +576,23 @@ int16_t ACMGenericCodec::InitEncoderSafe(WebRtcACMCodecParams* codec_params,
if (in_audio_ == NULL) {
return -1;
}
memset(in_audio_, 0, AUDIO_BUFFER_SIZE_W16 * sizeof(int16_t));
}
if (in_timestamp_ == NULL) {
in_timestamp_ = new uint32_t[TIMESTAMP_BUFFER_SIZE_W32];
if (in_timestamp_ == NULL) {
return -1;
}
memset(in_timestamp_, 0, sizeof(uint32_t) * TIMESTAMP_BUFFER_SIZE_W32);
}
// Fresh start for audio buffer.
is_audio_buff_fresh_ = true;
memset(in_audio_, 0, AUDIO_BUFFER_SIZE_W16 * sizeof(int16_t));
memset(in_timestamp_, 0, sizeof(uint32_t) * TIMESTAMP_BUFFER_SIZE_W32);
in_audio_ix_write_ = 0;
in_audio_ix_read_ = 0;
in_timestamp_ix_write_ = 0;
}
status = SetVADSafe(&codec_params->enable_dtx, &codec_params->enable_vad,
&codec_params->vad_mode);
return status;
}