Dual-stream implementation, not including VoE APIs.
Review URL: https://webrtc-codereview.appspot.com/933015 git-svn-id: http://webrtc.googlecode.com/svn/trunk@3230 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@ -29,7 +29,7 @@ enum {
|
||||
|
||||
// Interval for sending new CNG parameters (SID frames) is 100 msec.
|
||||
enum {
|
||||
kAcmSidIntervalMsec = 100
|
||||
kCngSidIntervalMsec = 100
|
||||
};
|
||||
|
||||
// We set some of the variables to invalid values as a check point
|
||||
@ -70,7 +70,6 @@ ACMGenericCodec::ACMGenericCodec()
|
||||
for (int i = 0; i < MAX_FRAME_SIZE_10MSEC; i++) {
|
||||
_vadLabel[i] = 0;
|
||||
}
|
||||
|
||||
// Nullify memory for encoder and decoder, and set payload type to an
|
||||
// invalid value.
|
||||
memset(&_encoderParams, 0, sizeof(WebRtcACMCodecParams));
|
||||
@ -143,7 +142,7 @@ int32_t ACMGenericCodec::Add10MsDataSafe(const uint32_t timestamp,
|
||||
|
||||
_lastTimestamp = timestamp;
|
||||
|
||||
// If the data exceeds the buffer size, we through away the oldest data and
|
||||
// If the data exceeds the buffer size, we throw away the oldest data and
|
||||
// add the newly received 10 msec at the end.
|
||||
if ((_inAudioIxWrite + lengthSmpl * audioChannel) > AUDIO_BUFFER_SIZE_W16) {
|
||||
// Get the number of samples to be overwritten.
|
||||
@ -191,29 +190,27 @@ int32_t ACMGenericCodec::Add10MsDataSafe(const uint32_t timestamp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ACMGenericCodec::HasFrameToEncode() const {
|
||||
ReadLockScoped lockCodec(_codecWrapperLock);
|
||||
if (_inAudioIxWrite < _frameLenSmpl * _noChannels)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int16_t ACMGenericCodec::Encode(uint8_t* bitStream,
|
||||
int16_t* bitStreamLenByte,
|
||||
uint32_t* timeStamp,
|
||||
WebRtcACMEncodingType* encodingType) {
|
||||
WriteLockScoped lockCodec(_codecWrapperLock);
|
||||
ReadLockScoped lockNetEq(*_netEqDecodeLock);
|
||||
return EncodeSafe(bitStream, bitStreamLenByte, timeStamp, encodingType);
|
||||
}
|
||||
|
||||
int16_t ACMGenericCodec::EncodeSafe(uint8_t* bitStream,
|
||||
int16_t* bitStreamLenByte,
|
||||
uint32_t* timeStamp,
|
||||
WebRtcACMEncodingType* encodingType) {
|
||||
// Only encode if we have enough data to encode. If not wait until we have a
|
||||
// full frame to encode.
|
||||
if (_inAudioIxWrite < _frameLenSmpl * _noChannels) {
|
||||
// There is not enough audio.
|
||||
if (!HasFrameToEncode()) {
|
||||
// There is not enough audio
|
||||
*timeStamp = 0;
|
||||
*bitStreamLenByte = 0;
|
||||
// Doesn't really matter what this parameter set to.
|
||||
// Doesn't really matter what this parameter set to
|
||||
*encodingType = kNoEncoding;
|
||||
return 0;
|
||||
}
|
||||
WriteLockScoped lockCodec(_codecWrapperLock);
|
||||
ReadLockScoped lockNetEq(*_netEqDecodeLock);
|
||||
|
||||
// Not all codecs accept the whole frame to be pushed into encoder at once.
|
||||
// Some codecs needs to be feed with a specific number of samples different
|
||||
@ -230,7 +227,6 @@ int16_t ACMGenericCodec::EncodeSafe(uint8_t* bitStream,
|
||||
"EncodeSafe: error, basic coding sample block is negative");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// This makes the internal encoder read from the beginning of the buffer.
|
||||
_inAudioIxRead = 0;
|
||||
*timeStamp = _inTimestamp[0];
|
||||
@ -932,7 +928,7 @@ int16_t ACMGenericCodec::EnableDTX() {
|
||||
}
|
||||
uint16_t freqHz;
|
||||
EncoderSampFreq(freqHz);
|
||||
if (WebRtcCng_InitEnc(_ptrDTXInst, freqHz, kAcmSidIntervalMsec,
|
||||
if (WebRtcCng_InitEnc(_ptrDTXInst, freqHz, kCngSidIntervalMsec,
|
||||
_numLPCParams) < 0) {
|
||||
// Couldn't initialize, has to return -1, and free the memory.
|
||||
WebRtcCng_FreeEnc(_ptrDTXInst);
|
||||
|
@ -711,20 +711,20 @@ class ACMGenericCodec {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// REDPayloadISAC()
|
||||
// This is an iSAC-specific function. The function is called to get RED
|
||||
// paylaod from a default-encoder.
|
||||
// payload from a default-encoder.
|
||||
//
|
||||
// Inputs:
|
||||
// -isacRate : the target rate of the main payload. A RED
|
||||
// paylaod is generated according to the rate of
|
||||
// main paylaod. Note that we are not specifying the
|
||||
// payload is generated according to the rate of
|
||||
// main payload. Note that we are not specifying the
|
||||
// rate of RED payload, but the main payload.
|
||||
// -isacBwEstimate : bandwidth information should be inserted in
|
||||
// RED payload.
|
||||
//
|
||||
// Output:
|
||||
// -payload : pointer to a buffer where the RED paylaod will
|
||||
// -payload : pointer to a buffer where the RED payload will
|
||||
// written to.
|
||||
// -paylaodLenBytes : a place-holder to write the length of the RED
|
||||
// -payloadLenBytes : a place-holder to write the length of the RED
|
||||
// payload in Bytes.
|
||||
//
|
||||
// Return value:
|
||||
@ -749,6 +749,13 @@ class ACMGenericCodec {
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// HasFrameToEncode()
|
||||
// Returns true if there is enough audio buffered for encoding, such that
|
||||
// calling Encode() will return a payload.
|
||||
//
|
||||
bool HasFrameToEncode() const;
|
||||
|
||||
protected:
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// All the functions with FunctionNameSafe(...) contain the actual
|
||||
@ -758,15 +765,6 @@ class ACMGenericCodec {
|
||||
// and return value we refer to FunctionName()
|
||||
//
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// See Encode() for the description of function, input(s)/output(s) and
|
||||
// return value.
|
||||
//
|
||||
WebRtc_Word16 EncodeSafe(WebRtc_UWord8* bitStream,
|
||||
WebRtc_Word16* bitStreamLenByte,
|
||||
WebRtc_UWord32* timeStamp,
|
||||
WebRtcACMEncodingType* encodingType);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// See Decode() for the description of function, input(s)/output(s) and
|
||||
// return value.
|
||||
|
@ -119,6 +119,10 @@
|
||||
'<(webrtc_root)/test/test.gyp:test_support_main',
|
||||
'<(DEPTH)/testing/gtest.gyp:gtest',
|
||||
'<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
|
||||
'<(webrtc_root)/modules/modules.gyp:webrtc_utility',
|
||||
],
|
||||
'include_dirs': [
|
||||
'<(webrtc_root)/common_audio/resampler/include',
|
||||
],
|
||||
'defines': [
|
||||
'<@(audio_coding_defines)',
|
||||
@ -127,6 +131,7 @@
|
||||
'../test/ACMTest.cc',
|
||||
'../test/APITest.cc',
|
||||
'../test/Channel.cc',
|
||||
'../test/dual_stream_unittest.cc',
|
||||
'../test/EncodeDecodeTest.cc',
|
||||
'../test/iSACTest.cc',
|
||||
'../test/PCMFile.cc',
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,7 @@
|
||||
#include "acm_resampler.h"
|
||||
#include "common_types.h"
|
||||
#include "engine_configurations.h"
|
||||
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -59,6 +60,17 @@ class AudioCodingModuleImpl : public AudioCodingModule {
|
||||
// Can be called multiple times for Codec, CNG, RED.
|
||||
WebRtc_Word32 RegisterSendCodec(const CodecInst& send_codec);
|
||||
|
||||
// Register Secondary codec for dual-streaming. Dual-streaming is activated
|
||||
// right after the secondary codec is registered.
|
||||
int RegisterSecondarySendCodec(const CodecInst& send_codec);
|
||||
|
||||
// Unregister the secondary codec. Dual-streaming is deactivated right after
|
||||
// deregistering secondary codec.
|
||||
void UnregisterSecondarySendCodec();
|
||||
|
||||
// Get the secondary codec.
|
||||
int SecondarySendCodec(CodecInst* secondary_codec) const;
|
||||
|
||||
// Get current send codec.
|
||||
WebRtc_Word32 SendCodec(CodecInst& current_codec) const;
|
||||
|
||||
@ -248,6 +260,35 @@ class AudioCodingModuleImpl : public AudioCodingModule {
|
||||
WebRtc_Word16 mirror_id,
|
||||
ACMNetEQ::JB jitter_buffer);
|
||||
|
||||
// Set VAD/DTX status. This function does not acquire a lock, and it is
|
||||
// created to be called only from inside a critical section.
|
||||
int SetVADSafe(bool enable_dtx, bool enable_vad, ACMVADMode mode);
|
||||
|
||||
// Process buffered audio when dual-streaming is not enabled (When RED is
|
||||
// enabled still this function is used.)
|
||||
int ProcessSingleStream();
|
||||
|
||||
// Process buffered audio when dual-streaming is enabled, i.e. secondary send
|
||||
// codec is registered.
|
||||
int ProcessDualStream();
|
||||
|
||||
// Preprocessing of input audio, including resampling and down-mixing if
|
||||
// required, before pushing audio into encoder'r buffer.
|
||||
//
|
||||
// in_frame: input audio-frame
|
||||
// out_frame: output audio_frame, the output is valid only if a preprocessing
|
||||
// is required.
|
||||
//
|
||||
// Return value:
|
||||
// -1: if encountering an error.
|
||||
// kPreprocessingSuccessful: if a preprocessing successfully performed.
|
||||
// kNoPreprocessingRequired: if there was no need for preprocessing. In
|
||||
// this case |out_frame| is not updated and
|
||||
// |in_frame| has to be used for further
|
||||
// operations.
|
||||
int PreprocessToAddData(const AudioFrame& in_frame,
|
||||
const AudioFrame** ptr_out);
|
||||
|
||||
private:
|
||||
// Change required states after starting to receive the codec corresponding
|
||||
// to |index|.
|
||||
@ -261,15 +302,12 @@ class AudioCodingModuleImpl : public AudioCodingModule {
|
||||
// is a stereo codec, RED or CN.
|
||||
bool IsCodecForSlave(int index) const;
|
||||
|
||||
// Returns true if the |codec| is RED.
|
||||
bool IsCodecRED(const CodecInst* codec) const;
|
||||
// ...or if its |index| is RED.
|
||||
bool IsCodecRED(int index) const;
|
||||
int EncodeFragmentation(int fragmentation_index, int payload_type,
|
||||
uint32_t current_timestamp,
|
||||
ACMGenericCodec* _secondary_encoder,
|
||||
uint8_t* stream);
|
||||
|
||||
// Returns true if the |codec| is CN.
|
||||
bool IsCodecCN(int index) const;
|
||||
// ...or if its |index| is CN.
|
||||
bool IsCodecCN(const CodecInst* codec) const;
|
||||
void ResetFragmentation(int vector_size);
|
||||
|
||||
AudioPacketizationCallback* _packetizationCallback;
|
||||
WebRtc_Word32 _id;
|
||||
@ -305,8 +343,15 @@ class AudioCodingModuleImpl : public AudioCodingModule {
|
||||
// RED/FEC.
|
||||
bool _isFirstRED;
|
||||
bool _fecEnabled;
|
||||
// TODO(turajs): |_redBuffer| is allocated in constructor, why having them
|
||||
// as pointers and not an array. If concerned about the memory, then make a
|
||||
// set-up function to allocate them only when they are going to be used, i.e.
|
||||
// FEC or Dual-streaming is enabled.
|
||||
WebRtc_UWord8* _redBuffer;
|
||||
RTPFragmentationHeader* _fragmentation;
|
||||
// TODO(turajs): we actually don't need |_fragmentation| as a member variable.
|
||||
// It is sufficient to keep the length & payload type of previous payload in
|
||||
// member variables.
|
||||
RTPFragmentationHeader _fragmentation;
|
||||
WebRtc_UWord32 _lastFECTimestamp;
|
||||
// If no RED is registered as receive codec this
|
||||
// will have an invalid value.
|
||||
@ -334,7 +379,9 @@ class AudioCodingModuleImpl : public AudioCodingModule {
|
||||
CriticalSectionWrapper* _callbackCritSect;
|
||||
|
||||
AudioFrame _audioFrame;
|
||||
|
||||
AudioFrame _preprocess_frame;
|
||||
CodecInst _secondarySendCodecInst;
|
||||
scoped_ptr<ACMGenericCodec> _secondaryEncoder;
|
||||
#ifdef ACM_QA_TEST
|
||||
FILE* _outgoingPL;
|
||||
FILE* _incomingPL;
|
||||
|
Reference in New Issue
Block a user