audio_coding: remove "main" directory

This is the last piece of the old directory layout of the modules.

Duplicated header files are left in audio_coding/main/include until
downstream code is updated to the new location. They have pragma
warnings added to them and identical header guards as the new headers to avoid breaking things.

BUG=webrtc:5095
TESTED=Passing compile-trybots with --clobber flag:
git cl try --clobber --bot=win_compile_rel --bot=linux_compile_rel --bot=android_compile_rel --bot=mac_compile_rel --bot=ios_rel --bot=linux_gn_rel --bot=win_x64_gn_rel --bot=mac_x64_gn_rel --bot=android_gn_rel -m tryserver.webrtc
NOTRY=True
NOPRESUBMIT=True

Review URL: https://codereview.webrtc.org/1481493004

Cr-Commit-Position: refs/heads/master@{#10803}
This commit is contained in:
kjellander
2015-11-26 04:44:54 -08:00
committed by Commit bot
parent a3c20bb9a0
commit 3e6db2321c
85 changed files with 1276 additions and 498 deletions

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_ACMTEST_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_ACMTEST_H_
class ACMTest {
public:
ACMTest() {}
virtual ~ACMTest() {}
virtual void Perform() = 0;
};
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_ACMTEST_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,163 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_APITEST_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_APITEST_H_
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/audio_coding/test/ACMTest.h"
#include "webrtc/modules/audio_coding/test/Channel.h"
#include "webrtc/modules/audio_coding/test/PCMFile.h"
#include "webrtc/modules/audio_coding/test/utility.h"
#include "webrtc/system_wrappers/include/event_wrapper.h"
#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
namespace webrtc {
class Config;
enum APITESTAction {
TEST_CHANGE_CODEC_ONLY = 0,
DTX_TEST = 1
};
class APITest : public ACMTest {
public:
explicit APITest(const Config& config);
~APITest();
void Perform();
private:
int16_t SetUp();
static bool PushAudioThreadA(void* obj);
static bool PullAudioThreadA(void* obj);
static bool ProcessThreadA(void* obj);
static bool APIThreadA(void* obj);
static bool PushAudioThreadB(void* obj);
static bool PullAudioThreadB(void* obj);
static bool ProcessThreadB(void* obj);
static bool APIThreadB(void* obj);
void CheckVADStatus(char side);
// Set Min delay, get delay, playout timestamp
void TestDelay(char side);
// Unregister a codec & register again.
void TestRegisteration(char side);
// Playout Mode, background noise mode.
// Receiver Frequency, playout frequency.
void TestPlayout(char receiveSide);
//
void TestSendVAD(char side);
void CurrentCodec(char side);
void ChangeCodec(char side);
void Wait(uint32_t waitLengthMs);
void RunTest(char thread);
bool PushAudioRunA();
bool PullAudioRunA();
bool ProcessRunA();
bool APIRunA();
bool PullAudioRunB();
bool PushAudioRunB();
bool ProcessRunB();
bool APIRunB();
//--- ACMs
rtc::scoped_ptr<AudioCodingModule> _acmA;
rtc::scoped_ptr<AudioCodingModule> _acmB;
//--- Channels
Channel* _channel_A2B;
Channel* _channel_B2A;
//--- I/O files
// A
PCMFile _inFileA;
PCMFile _outFileA;
// B
PCMFile _outFileB;
PCMFile _inFileB;
//--- I/O params
// A
int32_t _outFreqHzA;
// B
int32_t _outFreqHzB;
// Should we write to file.
// we might skip writing to file if we
// run the test for a long time.
bool _writeToFile;
//--- Events
// A
EventTimerWrapper* _pullEventA; // pulling data from ACM
EventTimerWrapper* _pushEventA; // pushing data to ACM
EventTimerWrapper* _processEventA; // process
EventWrapper* _apiEventA; // API calls
// B
EventTimerWrapper* _pullEventB; // pulling data from ACM
EventTimerWrapper* _pushEventB; // pushing data to ACM
EventTimerWrapper* _processEventB; // process
EventWrapper* _apiEventB; // API calls
// keep track of the codec in either side.
uint8_t _codecCntrA;
uint8_t _codecCntrB;
// Is set to true if there is no encoder in either side
bool _thereIsEncoderA;
bool _thereIsEncoderB;
bool _thereIsDecoderA;
bool _thereIsDecoderB;
bool _sendVADA;
bool _sendDTXA;
ACMVADMode _sendVADModeA;
bool _sendVADB;
bool _sendDTXB;
ACMVADMode _sendVADModeB;
int32_t _minDelayA;
int32_t _minDelayB;
bool _payloadUsed[32];
bool _verbose;
int _dotPositionA;
int _dotMoveDirectionA;
int _dotPositionB;
int _dotMoveDirectionB;
char _movingDot[41];
VADCallback* _vadCallbackA;
VADCallback* _vadCallbackB;
RWLockWrapper& _apiTestRWLock;
bool _randomTest;
int _testNumA;
int _testNumB;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_APITEST_H_

View File

@ -0,0 +1,424 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_coding/test/Channel.h"
#include <assert.h>
#include <iostream>
#include "webrtc/base/format_macros.h"
#include "webrtc/system_wrappers/include/tick_util.h"
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
namespace webrtc {
int32_t Channel::SendData(FrameType frameType,
uint8_t payloadType,
uint32_t timeStamp,
const uint8_t* payloadData,
size_t payloadSize,
const RTPFragmentationHeader* fragmentation) {
WebRtcRTPHeader rtpInfo;
int32_t status;
size_t payloadDataSize = payloadSize;
rtpInfo.header.markerBit = false;
rtpInfo.header.ssrc = 0;
rtpInfo.header.sequenceNumber = (external_sequence_number_ < 0) ?
_seqNo++ : static_cast<uint16_t>(external_sequence_number_);
rtpInfo.header.payloadType = payloadType;
rtpInfo.header.timestamp = (external_send_timestamp_ < 0) ? timeStamp :
static_cast<uint32_t>(external_send_timestamp_);
if (frameType == kAudioFrameCN) {
rtpInfo.type.Audio.isCNG = true;
} else {
rtpInfo.type.Audio.isCNG = false;
}
if (frameType == kEmptyFrame) {
// When frame is empty, we should not transmit it. The frame size of the
// next non-empty frame will be based on the previous frame size.
_useLastFrameSize = _lastFrameSizeSample > 0;
return 0;
}
rtpInfo.type.Audio.channel = 1;
// Treat fragmentation separately
if (fragmentation != NULL) {
// If silence for too long, send only new data.
if ((fragmentation->fragmentationVectorSize == 2) &&
(fragmentation->fragmentationTimeDiff[1] <= 0x3fff)) {
// only 0x80 if we have multiple blocks
_payloadData[0] = 0x80 + fragmentation->fragmentationPlType[1];
size_t REDheader = (fragmentation->fragmentationTimeDiff[1] << 10) +
fragmentation->fragmentationLength[1];
_payloadData[1] = uint8_t((REDheader >> 16) & 0x000000FF);
_payloadData[2] = uint8_t((REDheader >> 8) & 0x000000FF);
_payloadData[3] = uint8_t(REDheader & 0x000000FF);
_payloadData[4] = fragmentation->fragmentationPlType[0];
// copy the RED data
memcpy(_payloadData + 5,
payloadData + fragmentation->fragmentationOffset[1],
fragmentation->fragmentationLength[1]);
// copy the normal data
memcpy(_payloadData + 5 + fragmentation->fragmentationLength[1],
payloadData + fragmentation->fragmentationOffset[0],
fragmentation->fragmentationLength[0]);
payloadDataSize += 5;
} else {
// single block (newest one)
memcpy(_payloadData, payloadData + fragmentation->fragmentationOffset[0],
fragmentation->fragmentationLength[0]);
payloadDataSize = fragmentation->fragmentationLength[0];
rtpInfo.header.payloadType = fragmentation->fragmentationPlType[0];
}
} else {
memcpy(_payloadData, payloadData, payloadDataSize);
if (_isStereo) {
if (_leftChannel) {
memcpy(&_rtpInfo, &rtpInfo, sizeof(WebRtcRTPHeader));
_leftChannel = false;
rtpInfo.type.Audio.channel = 1;
} else {
memcpy(&rtpInfo, &_rtpInfo, sizeof(WebRtcRTPHeader));
_leftChannel = true;
rtpInfo.type.Audio.channel = 2;
}
}
}
_channelCritSect->Enter();
if (_saveBitStream) {
//fwrite(payloadData, sizeof(uint8_t), payloadSize, _bitStreamFile);
}
if (!_isStereo) {
CalcStatistics(rtpInfo, payloadSize);
}
_useLastFrameSize = false;
_lastInTimestamp = timeStamp;
_totalBytes += payloadDataSize;
_channelCritSect->Leave();
if (_useFECTestWithPacketLoss) {
_packetLoss += 1;
if (_packetLoss == 3) {
_packetLoss = 0;
return 0;
}
}
if (num_packets_to_drop_ > 0) {
num_packets_to_drop_--;
return 0;
}
status = _receiverACM->IncomingPacket(_payloadData, payloadDataSize, rtpInfo);
return status;
}
// TODO(turajs): rewite this method.
void Channel::CalcStatistics(WebRtcRTPHeader& rtpInfo, size_t payloadSize) {
int n;
if ((rtpInfo.header.payloadType != _lastPayloadType)
&& (_lastPayloadType != -1)) {
// payload-type is changed.
// we have to terminate the calculations on the previous payload type
// we ignore the last packet in that payload type just to make things
// easier.
for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
if (_lastPayloadType == _payloadStats[n].payloadType) {
_payloadStats[n].newPacket = true;
break;
}
}
}
_lastPayloadType = rtpInfo.header.payloadType;
bool newPayload = true;
ACMTestPayloadStats* currentPayloadStr = NULL;
for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
if (rtpInfo.header.payloadType == _payloadStats[n].payloadType) {
newPayload = false;
currentPayloadStr = &_payloadStats[n];
break;
}
}
if (!newPayload) {
if (!currentPayloadStr->newPacket) {
if (!_useLastFrameSize) {
_lastFrameSizeSample = (uint32_t) ((uint32_t) rtpInfo.header.timestamp -
(uint32_t) currentPayloadStr->lastTimestamp);
}
assert(_lastFrameSizeSample > 0);
int k = 0;
for (; k < MAX_NUM_FRAMESIZES; ++k) {
if ((currentPayloadStr->frameSizeStats[k].frameSizeSample ==
_lastFrameSizeSample) ||
(currentPayloadStr->frameSizeStats[k].frameSizeSample == 0)) {
break;
}
}
if (k == MAX_NUM_FRAMESIZES) {
// New frame size found but no space to count statistics on it. Skip it.
printf("No memory to store statistics for payload %d : frame size %d\n",
_lastPayloadType, _lastFrameSizeSample);
return;
}
ACMTestFrameSizeStats* currentFrameSizeStats = &(currentPayloadStr
->frameSizeStats[k]);
currentFrameSizeStats->frameSizeSample = (int16_t) _lastFrameSizeSample;
// increment the number of encoded samples.
currentFrameSizeStats->totalEncodedSamples += _lastFrameSizeSample;
// increment the number of recveived packets
currentFrameSizeStats->numPackets++;
// increment the total number of bytes (this is based on
// the previous payload we don't know the frame-size of
// the current payload.
currentFrameSizeStats->totalPayloadLenByte += currentPayloadStr
->lastPayloadLenByte;
// store the maximum payload-size (this is based on
// the previous payload we don't know the frame-size of
// the current payload.
if (currentFrameSizeStats->maxPayloadLen
< currentPayloadStr->lastPayloadLenByte) {
currentFrameSizeStats->maxPayloadLen = currentPayloadStr
->lastPayloadLenByte;
}
// store the current values for the next time
currentPayloadStr->lastTimestamp = rtpInfo.header.timestamp;
currentPayloadStr->lastPayloadLenByte = payloadSize;
} else {
currentPayloadStr->newPacket = false;
currentPayloadStr->lastPayloadLenByte = payloadSize;
currentPayloadStr->lastTimestamp = rtpInfo.header.timestamp;
currentPayloadStr->payloadType = rtpInfo.header.payloadType;
memset(currentPayloadStr->frameSizeStats, 0, MAX_NUM_FRAMESIZES *
sizeof(ACMTestFrameSizeStats));
}
} else {
n = 0;
while (_payloadStats[n].payloadType != -1) {
n++;
}
// first packet
_payloadStats[n].newPacket = false;
_payloadStats[n].lastPayloadLenByte = payloadSize;
_payloadStats[n].lastTimestamp = rtpInfo.header.timestamp;
_payloadStats[n].payloadType = rtpInfo.header.payloadType;
memset(_payloadStats[n].frameSizeStats, 0, MAX_NUM_FRAMESIZES *
sizeof(ACMTestFrameSizeStats));
}
}
Channel::Channel(int16_t chID)
: _receiverACM(NULL),
_seqNo(0),
_channelCritSect(CriticalSectionWrapper::CreateCriticalSection()),
_bitStreamFile(NULL),
_saveBitStream(false),
_lastPayloadType(-1),
_isStereo(false),
_leftChannel(true),
_lastInTimestamp(0),
_useLastFrameSize(false),
_lastFrameSizeSample(0),
_packetLoss(0),
_useFECTestWithPacketLoss(false),
_beginTime(TickTime::MillisecondTimestamp()),
_totalBytes(0),
external_send_timestamp_(-1),
external_sequence_number_(-1),
num_packets_to_drop_(0) {
int n;
int k;
for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
_payloadStats[n].payloadType = -1;
_payloadStats[n].newPacket = true;
for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
_payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
_payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
_payloadStats[n].frameSizeStats[k].numPackets = 0;
_payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
_payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
}
}
if (chID >= 0) {
_saveBitStream = true;
char bitStreamFileName[500];
sprintf(bitStreamFileName, "bitStream_%d.dat", chID);
_bitStreamFile = fopen(bitStreamFileName, "wb");
} else {
_saveBitStream = false;
}
}
Channel::~Channel() {
delete _channelCritSect;
}
void Channel::RegisterReceiverACM(AudioCodingModule* acm) {
_receiverACM = acm;
return;
}
void Channel::ResetStats() {
int n;
int k;
_channelCritSect->Enter();
_lastPayloadType = -1;
for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
_payloadStats[n].payloadType = -1;
_payloadStats[n].newPacket = true;
for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
_payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
_payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
_payloadStats[n].frameSizeStats[k].numPackets = 0;
_payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
_payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
}
}
_beginTime = TickTime::MillisecondTimestamp();
_totalBytes = 0;
_channelCritSect->Leave();
}
int16_t Channel::Stats(CodecInst& codecInst,
ACMTestPayloadStats& payloadStats) {
_channelCritSect->Enter();
int n;
payloadStats.payloadType = -1;
for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
if (_payloadStats[n].payloadType == codecInst.pltype) {
memcpy(&payloadStats, &_payloadStats[n], sizeof(ACMTestPayloadStats));
break;
}
}
if (payloadStats.payloadType == -1) {
_channelCritSect->Leave();
return -1;
}
for (n = 0; n < MAX_NUM_FRAMESIZES; n++) {
if (payloadStats.frameSizeStats[n].frameSizeSample == 0) {
_channelCritSect->Leave();
return 0;
}
payloadStats.frameSizeStats[n].usageLenSec = (double) payloadStats
.frameSizeStats[n].totalEncodedSamples / (double) codecInst.plfreq;
payloadStats.frameSizeStats[n].rateBitPerSec =
payloadStats.frameSizeStats[n].totalPayloadLenByte * 8
/ payloadStats.frameSizeStats[n].usageLenSec;
}
_channelCritSect->Leave();
return 0;
}
void Channel::Stats(uint32_t* numPackets) {
_channelCritSect->Enter();
int k;
int n;
memset(numPackets, 0, MAX_NUM_PAYLOADS * sizeof(uint32_t));
for (k = 0; k < MAX_NUM_PAYLOADS; k++) {
if (_payloadStats[k].payloadType == -1) {
break;
}
numPackets[k] = 0;
for (n = 0; n < MAX_NUM_FRAMESIZES; n++) {
if (_payloadStats[k].frameSizeStats[n].frameSizeSample == 0) {
break;
}
numPackets[k] += _payloadStats[k].frameSizeStats[n].numPackets;
}
}
_channelCritSect->Leave();
}
void Channel::Stats(uint8_t* payloadType, uint32_t* payloadLenByte) {
_channelCritSect->Enter();
int k;
int n;
memset(payloadLenByte, 0, MAX_NUM_PAYLOADS * sizeof(uint32_t));
for (k = 0; k < MAX_NUM_PAYLOADS; k++) {
if (_payloadStats[k].payloadType == -1) {
break;
}
payloadType[k] = (uint8_t) _payloadStats[k].payloadType;
payloadLenByte[k] = 0;
for (n = 0; n < MAX_NUM_FRAMESIZES; n++) {
if (_payloadStats[k].frameSizeStats[n].frameSizeSample == 0) {
break;
}
payloadLenByte[k] += (uint16_t) _payloadStats[k].frameSizeStats[n]
.totalPayloadLenByte;
}
}
_channelCritSect->Leave();
}
void Channel::PrintStats(CodecInst& codecInst) {
ACMTestPayloadStats payloadStats;
Stats(codecInst, payloadStats);
printf("%s %d kHz\n", codecInst.plname, codecInst.plfreq / 1000);
printf("=====================================================\n");
if (payloadStats.payloadType == -1) {
printf("No Packets are sent with payload-type %d (%s)\n\n",
codecInst.pltype, codecInst.plname);
return;
}
for (int k = 0; k < MAX_NUM_FRAMESIZES; k++) {
if (payloadStats.frameSizeStats[k].frameSizeSample == 0) {
break;
}
printf("Frame-size.................... %d samples\n",
payloadStats.frameSizeStats[k].frameSizeSample);
printf("Average Rate.................. %.0f bits/sec\n",
payloadStats.frameSizeStats[k].rateBitPerSec);
printf("Maximum Payload-Size.......... %" PRIuS " Bytes\n",
payloadStats.frameSizeStats[k].maxPayloadLen);
printf(
"Maximum Instantaneous Rate.... %.0f bits/sec\n",
((double) payloadStats.frameSizeStats[k].maxPayloadLen * 8.0
* (double) codecInst.plfreq)
/ (double) payloadStats.frameSizeStats[k].frameSizeSample);
printf("Number of Packets............. %u\n",
(unsigned int) payloadStats.frameSizeStats[k].numPackets);
printf("Duration...................... %0.3f sec\n\n",
payloadStats.frameSizeStats[k].usageLenSec);
}
}
uint32_t Channel::LastInTimestamp() {
uint32_t timestamp;
_channelCritSect->Enter();
timestamp = _lastInTimestamp;
_channelCritSect->Leave();
return timestamp;
}
double Channel::BitRate() {
double rate;
uint64_t currTime = TickTime::MillisecondTimestamp();
_channelCritSect->Enter();
rate = ((double) _totalBytes * 8.0) / (double) (currTime - _beginTime);
_channelCritSect->Leave();
return rate;
}
} // namespace webrtc

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_CHANNEL_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_CHANNEL_H_
#include <stdio.h>
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/typedefs.h"
namespace webrtc {
class CriticalSectionWrapper;
#define MAX_NUM_PAYLOADS 50
#define MAX_NUM_FRAMESIZES 6
// TODO(turajs): Write constructor for this structure.
struct ACMTestFrameSizeStats {
uint16_t frameSizeSample;
size_t maxPayloadLen;
uint32_t numPackets;
uint64_t totalPayloadLenByte;
uint64_t totalEncodedSamples;
double rateBitPerSec;
double usageLenSec;
};
// TODO(turajs): Write constructor for this structure.
struct ACMTestPayloadStats {
bool newPacket;
int16_t payloadType;
size_t lastPayloadLenByte;
uint32_t lastTimestamp;
ACMTestFrameSizeStats frameSizeStats[MAX_NUM_FRAMESIZES];
};
class Channel : public AudioPacketizationCallback {
public:
Channel(int16_t chID = -1);
~Channel();
int32_t SendData(FrameType frameType,
uint8_t payloadType,
uint32_t timeStamp,
const uint8_t* payloadData,
size_t payloadSize,
const RTPFragmentationHeader* fragmentation) override;
void RegisterReceiverACM(AudioCodingModule *acm);
void ResetStats();
int16_t Stats(CodecInst& codecInst, ACMTestPayloadStats& payloadStats);
void Stats(uint32_t* numPackets);
void Stats(uint8_t* payloadType, uint32_t* payloadLenByte);
void PrintStats(CodecInst& codecInst);
void SetIsStereo(bool isStereo) {
_isStereo = isStereo;
}
uint32_t LastInTimestamp();
void SetFECTestWithPacketLoss(bool usePacketLoss) {
_useFECTestWithPacketLoss = usePacketLoss;
}
double BitRate();
void set_send_timestamp(uint32_t new_send_ts) {
external_send_timestamp_ = new_send_ts;
}
void set_sequence_number(uint16_t new_sequence_number) {
external_sequence_number_ = new_sequence_number;
}
void set_num_packets_to_drop(int new_num_packets_to_drop) {
num_packets_to_drop_ = new_num_packets_to_drop;
}
private:
void CalcStatistics(WebRtcRTPHeader& rtpInfo, size_t payloadSize);
AudioCodingModule* _receiverACM;
uint16_t _seqNo;
// 60msec * 32 sample(max)/msec * 2 description (maybe) * 2 bytes/sample
uint8_t _payloadData[60 * 32 * 2 * 2];
CriticalSectionWrapper* _channelCritSect;
FILE* _bitStreamFile;
bool _saveBitStream;
int16_t _lastPayloadType;
ACMTestPayloadStats _payloadStats[MAX_NUM_PAYLOADS];
bool _isStereo;
WebRtcRTPHeader _rtpInfo;
bool _leftChannel;
uint32_t _lastInTimestamp;
bool _useLastFrameSize;
uint32_t _lastFrameSizeSample;
// FEC Test variables
int16_t _packetLoss;
bool _useFECTestWithPacketLoss;
uint64_t _beginTime;
uint64_t _totalBytes;
// External timing info, defaulted to -1. Only used if they are
// non-negative.
int64_t external_send_timestamp_;
int32_t external_sequence_number_;
int num_packets_to_drop_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_CHANNEL_H_

View File

@ -0,0 +1,351 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_coding/test/EncodeDecodeTest.h"
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/audio_coding/acm2/acm_common_defs.h"
#include "webrtc/modules/audio_coding/test/utility.h"
#include "webrtc/system_wrappers/include/trace.h"
#include "webrtc/test/testsupport/fileutils.h"
namespace webrtc {
TestPacketization::TestPacketization(RTPStream *rtpStream, uint16_t frequency)
: _rtpStream(rtpStream),
_frequency(frequency),
_seqNo(0) {
}
TestPacketization::~TestPacketization() {
}
int32_t TestPacketization::SendData(
const FrameType /* frameType */, const uint8_t payloadType,
const uint32_t timeStamp, const uint8_t* payloadData,
const size_t payloadSize,
const RTPFragmentationHeader* /* fragmentation */) {
_rtpStream->Write(payloadType, timeStamp, _seqNo++, payloadData, payloadSize,
_frequency);
return 1;
}
Sender::Sender()
: _acm(NULL),
_pcmFile(),
_audioFrame(),
_packetization(NULL) {
}
void Sender::Setup(AudioCodingModule *acm, RTPStream *rtpStream,
std::string in_file_name, int sample_rate, int channels) {
struct CodecInst sendCodec;
int noOfCodecs = acm->NumberOfCodecs();
int codecNo;
// Open input file
const std::string file_name = webrtc::test::ResourcePath(in_file_name, "pcm");
_pcmFile.Open(file_name, sample_rate, "rb");
if (channels == 2) {
_pcmFile.ReadStereo(true);
}
// Set the codec for the current test.
if ((testMode == 0) || (testMode == 1)) {
// Set the codec id.
codecNo = codeId;
} else {
// Choose codec on command line.
printf("List of supported codec.\n");
for (int n = 0; n < noOfCodecs; n++) {
EXPECT_EQ(0, acm->Codec(n, &sendCodec));
printf("%d %s\n", n, sendCodec.plname);
}
printf("Choose your codec:");
ASSERT_GT(scanf("%d", &codecNo), 0);
}
EXPECT_EQ(0, acm->Codec(codecNo, &sendCodec));
sendCodec.channels = channels;
EXPECT_EQ(0, acm->RegisterSendCodec(sendCodec));
_packetization = new TestPacketization(rtpStream, sendCodec.plfreq);
EXPECT_EQ(0, acm->RegisterTransportCallback(_packetization));
_acm = acm;
}
void Sender::Teardown() {
_pcmFile.Close();
delete _packetization;
}
bool Sender::Add10MsData() {
if (!_pcmFile.EndOfFile()) {
EXPECT_GT(_pcmFile.Read10MsData(_audioFrame), 0);
int32_t ok = _acm->Add10MsData(_audioFrame);
EXPECT_GE(ok, 0);
return ok >= 0 ? true : false;
}
return false;
}
void Sender::Run() {
while (true) {
if (!Add10MsData()) {
break;
}
}
}
Receiver::Receiver()
: _playoutLengthSmpls(WEBRTC_10MS_PCM_AUDIO),
_payloadSizeBytes(MAX_INCOMING_PAYLOAD) {
}
void Receiver::Setup(AudioCodingModule *acm, RTPStream *rtpStream,
std::string out_file_name, int channels) {
struct CodecInst recvCodec = CodecInst();
int noOfCodecs;
EXPECT_EQ(0, acm->InitializeReceiver());
noOfCodecs = acm->NumberOfCodecs();
for (int i = 0; i < noOfCodecs; i++) {
EXPECT_EQ(0, acm->Codec(i, &recvCodec));
if (recvCodec.channels == channels)
EXPECT_EQ(0, acm->RegisterReceiveCodec(recvCodec));
// Forces mono/stereo for Opus.
if (!strcmp(recvCodec.plname, "opus")) {
recvCodec.channels = channels;
EXPECT_EQ(0, acm->RegisterReceiveCodec(recvCodec));
}
}
int playSampFreq;
std::string file_name;
std::stringstream file_stream;
file_stream << webrtc::test::OutputPath() << out_file_name
<< static_cast<int>(codeId) << ".pcm";
file_name = file_stream.str();
_rtpStream = rtpStream;
if (testMode == 1) {
playSampFreq = recvCodec.plfreq;
_pcmFile.Open(file_name, recvCodec.plfreq, "wb+");
} else if (testMode == 0) {
playSampFreq = 32000;
_pcmFile.Open(file_name, 32000, "wb+");
} else {
printf("\nValid output frequencies:\n");
printf("8000\n16000\n32000\n-1,");
printf("which means output frequency equal to received signal frequency");
printf("\n\nChoose output sampling frequency: ");
ASSERT_GT(scanf("%d", &playSampFreq), 0);
file_name = webrtc::test::OutputPath() + out_file_name + ".pcm";
_pcmFile.Open(file_name, playSampFreq, "wb+");
}
_realPayloadSizeBytes = 0;
_playoutBuffer = new int16_t[WEBRTC_10MS_PCM_AUDIO];
_frequency = playSampFreq;
_acm = acm;
_firstTime = true;
}
void Receiver::Teardown() {
delete[] _playoutBuffer;
_pcmFile.Close();
if (testMode > 1) {
Trace::ReturnTrace();
}
}
bool Receiver::IncomingPacket() {
if (!_rtpStream->EndOfFile()) {
if (_firstTime) {
_firstTime = false;
_realPayloadSizeBytes = _rtpStream->Read(&_rtpInfo, _incomingPayload,
_payloadSizeBytes, &_nextTime);
if (_realPayloadSizeBytes == 0) {
if (_rtpStream->EndOfFile()) {
_firstTime = true;
return true;
} else {
return false;
}
}
}
EXPECT_EQ(0, _acm->IncomingPacket(_incomingPayload, _realPayloadSizeBytes,
_rtpInfo));
_realPayloadSizeBytes = _rtpStream->Read(&_rtpInfo, _incomingPayload,
_payloadSizeBytes, &_nextTime);
if (_realPayloadSizeBytes == 0 && _rtpStream->EndOfFile()) {
_firstTime = true;
}
}
return true;
}
bool Receiver::PlayoutData() {
AudioFrame audioFrame;
int32_t ok =_acm->PlayoutData10Ms(_frequency, &audioFrame);
EXPECT_EQ(0, ok);
if (ok < 0){
return false;
}
if (_playoutLengthSmpls == 0) {
return false;
}
_pcmFile.Write10MsData(audioFrame.data_,
audioFrame.samples_per_channel_ * audioFrame.num_channels_);
return true;
}
void Receiver::Run() {
uint8_t counter500Ms = 50;
uint32_t clock = 0;
while (counter500Ms > 0) {
if (clock == 0 || clock >= _nextTime) {
EXPECT_TRUE(IncomingPacket());
if (clock == 0) {
clock = _nextTime;
}
}
if ((clock % 10) == 0) {
if (!PlayoutData()) {
clock++;
continue;
}
}
if (_rtpStream->EndOfFile()) {
counter500Ms--;
}
clock++;
}
}
EncodeDecodeTest::EncodeDecodeTest() {
_testMode = 2;
Trace::CreateTrace();
Trace::SetTraceFile(
(webrtc::test::OutputPath() + "acm_encdec_trace.txt").c_str());
}
EncodeDecodeTest::EncodeDecodeTest(int testMode) {
//testMode == 0 for autotest
//testMode == 1 for testing all codecs/parameters
//testMode > 1 for specific user-input test (as it was used before)
_testMode = testMode;
if (_testMode != 0) {
Trace::CreateTrace();
Trace::SetTraceFile(
(webrtc::test::OutputPath() + "acm_encdec_trace.txt").c_str());
}
}
void EncodeDecodeTest::Perform() {
int numCodecs = 1;
int codePars[3]; // Frequency, packet size, rate.
int numPars[52]; // Number of codec parameters sets (freq, pacsize, rate)
// to test, for a given codec.
codePars[0] = 0;
codePars[1] = 0;
codePars[2] = 0;
rtc::scoped_ptr<AudioCodingModule> acm(AudioCodingModule::Create(0));
struct CodecInst sendCodecTmp;
numCodecs = acm->NumberOfCodecs();
if (_testMode != 2) {
for (int n = 0; n < numCodecs; n++) {
EXPECT_EQ(0, acm->Codec(n, &sendCodecTmp));
if (STR_CASE_CMP(sendCodecTmp.plname, "telephone-event") == 0) {
numPars[n] = 0;
} else if (STR_CASE_CMP(sendCodecTmp.plname, "cn") == 0) {
numPars[n] = 0;
} else if (STR_CASE_CMP(sendCodecTmp.plname, "red") == 0) {
numPars[n] = 0;
} else if (sendCodecTmp.channels == 2) {
numPars[n] = 0;
} else {
numPars[n] = 1;
}
}
} else {
numCodecs = 1;
numPars[0] = 1;
}
_receiver.testMode = _testMode;
// Loop over all mono codecs:
for (int codeId = 0; codeId < numCodecs; codeId++) {
// Only encode using real mono encoders, not telephone-event and cng.
for (int loopPars = 1; loopPars <= numPars[codeId]; loopPars++) {
// Encode all data to file.
std::string fileName = EncodeToFile(1, codeId, codePars, _testMode);
RTPFile rtpFile;
rtpFile.Open(fileName.c_str(), "rb");
_receiver.codeId = codeId;
rtpFile.ReadHeader();
_receiver.Setup(acm.get(), &rtpFile, "encodeDecode_out", 1);
_receiver.Run();
_receiver.Teardown();
rtpFile.Close();
}
}
// End tracing.
if (_testMode == 1) {
Trace::ReturnTrace();
}
}
std::string EncodeDecodeTest::EncodeToFile(int fileType,
int codeId,
int* codePars,
int testMode) {
rtc::scoped_ptr<AudioCodingModule> acm(AudioCodingModule::Create(1));
RTPFile rtpFile;
std::string fileName = webrtc::test::TempFilename(webrtc::test::OutputPath(),
"encode_decode_rtp");
rtpFile.Open(fileName.c_str(), "wb+");
rtpFile.WriteHeader();
// Store for auto_test and logging.
_sender.testMode = testMode;
_sender.codeId = codeId;
_sender.Setup(acm.get(), &rtpFile, "audio_coding/testfile32kHz", 32000, 1);
if (acm->SendCodec()) {
_sender.Run();
}
_sender.Teardown();
rtpFile.Close();
return fileName;
}
} // namespace webrtc

View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_ENCODEDECODETEST_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_ENCODEDECODETEST_H_
#include <stdio.h>
#include <string.h>
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/audio_coding/test/ACMTest.h"
#include "webrtc/modules/audio_coding/test/PCMFile.h"
#include "webrtc/modules/audio_coding/test/RTPFile.h"
#include "webrtc/typedefs.h"
namespace webrtc {
#define MAX_INCOMING_PAYLOAD 8096
// TestPacketization callback which writes the encoded payloads to file
class TestPacketization : public AudioPacketizationCallback {
public:
TestPacketization(RTPStream *rtpStream, uint16_t frequency);
~TestPacketization();
int32_t SendData(const FrameType frameType,
const uint8_t payloadType,
const uint32_t timeStamp,
const uint8_t* payloadData,
const size_t payloadSize,
const RTPFragmentationHeader* fragmentation) override;
private:
static void MakeRTPheader(uint8_t* rtpHeader, uint8_t payloadType,
int16_t seqNo, uint32_t timeStamp, uint32_t ssrc);
RTPStream* _rtpStream;
int32_t _frequency;
int16_t _seqNo;
};
class Sender {
public:
Sender();
void Setup(AudioCodingModule *acm, RTPStream *rtpStream,
std::string in_file_name, int sample_rate, int channels);
void Teardown();
void Run();
bool Add10MsData();
//for auto_test and logging
uint8_t testMode;
uint8_t codeId;
protected:
AudioCodingModule* _acm;
private:
PCMFile _pcmFile;
AudioFrame _audioFrame;
TestPacketization* _packetization;
};
class Receiver {
public:
Receiver();
virtual ~Receiver() {};
void Setup(AudioCodingModule *acm, RTPStream *rtpStream,
std::string out_file_name, int channels);
void Teardown();
void Run();
virtual bool IncomingPacket();
bool PlayoutData();
//for auto_test and logging
uint8_t codeId;
uint8_t testMode;
private:
PCMFile _pcmFile;
int16_t* _playoutBuffer;
uint16_t _playoutLengthSmpls;
int32_t _frequency;
bool _firstTime;
protected:
AudioCodingModule* _acm;
uint8_t _incomingPayload[MAX_INCOMING_PAYLOAD];
RTPStream* _rtpStream;
WebRtcRTPHeader _rtpInfo;
size_t _realPayloadSizeBytes;
size_t _payloadSizeBytes;
uint32_t _nextTime;
};
class EncodeDecodeTest : public ACMTest {
public:
EncodeDecodeTest();
explicit EncodeDecodeTest(int testMode);
void Perform() override;
uint16_t _playoutFreq;
uint8_t _testMode;
private:
std::string EncodeToFile(int fileType,
int codeId,
int* codePars,
int testMode);
protected:
Sender _sender;
Receiver _receiver;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_ENCODEDECODETEST_H_

View File

@ -0,0 +1,204 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "PCMFile.h"
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/include/module_common_types.h"
namespace webrtc {
#define MAX_FILE_NAME_LENGTH_BYTE 500
PCMFile::PCMFile()
: pcm_file_(NULL),
samples_10ms_(160),
frequency_(16000),
end_of_file_(false),
auto_rewind_(false),
rewinded_(false),
read_stereo_(false),
save_stereo_(false) {
timestamp_ = (((uint32_t) rand() & 0x0000FFFF) << 16) |
((uint32_t) rand() & 0x0000FFFF);
}
PCMFile::PCMFile(uint32_t timestamp)
: pcm_file_(NULL),
samples_10ms_(160),
frequency_(16000),
end_of_file_(false),
auto_rewind_(false),
rewinded_(false),
read_stereo_(false),
save_stereo_(false) {
timestamp_ = timestamp;
}
int16_t PCMFile::ChooseFile(std::string* file_name, int16_t max_len,
uint16_t* frequency_hz) {
char tmp_name[MAX_FILE_NAME_LENGTH_BYTE];
EXPECT_TRUE(fgets(tmp_name, MAX_FILE_NAME_LENGTH_BYTE, stdin) != NULL);
tmp_name[MAX_FILE_NAME_LENGTH_BYTE - 1] = '\0';
int16_t n = 0;
// Removing trailing spaces.
while ((isspace(tmp_name[n]) || iscntrl(tmp_name[n])) && (tmp_name[n] != 0)
&& (n < MAX_FILE_NAME_LENGTH_BYTE)) {
n++;
}
if (n > 0) {
memmove(tmp_name, &tmp_name[n], MAX_FILE_NAME_LENGTH_BYTE - n);
}
// Removing trailing spaces.
n = (int16_t)(strlen(tmp_name) - 1);
if (n >= 0) {
while ((isspace(tmp_name[n]) || iscntrl(tmp_name[n])) && (n >= 0)) {
n--;
}
}
if (n >= 0) {
tmp_name[n + 1] = '\0';
}
int16_t len = (int16_t) strlen(tmp_name);
if (len > max_len) {
return -1;
}
if (len > 0) {
std::string tmp_string(tmp_name, len + 1);
*file_name = tmp_string;
}
printf("Enter the sampling frequency (in Hz) of the above file [%u]: ",
*frequency_hz);
EXPECT_TRUE(fgets(tmp_name, 10, stdin) != NULL);
uint16_t tmp_frequency = (uint16_t) atoi(tmp_name);
if (tmp_frequency > 0) {
*frequency_hz = tmp_frequency;
}
return 0;
}
void PCMFile::Open(const std::string& file_name, uint16_t frequency,
const char* mode, bool auto_rewind) {
if ((pcm_file_ = fopen(file_name.c_str(), mode)) == NULL) {
printf("Cannot open file %s.\n", file_name.c_str());
ADD_FAILURE() << "Unable to read file";
}
frequency_ = frequency;
samples_10ms_ = (uint16_t)(frequency_ / 100);
auto_rewind_ = auto_rewind;
end_of_file_ = false;
rewinded_ = false;
}
int32_t PCMFile::SamplingFrequency() const {
return frequency_;
}
uint16_t PCMFile::PayloadLength10Ms() const {
return samples_10ms_;
}
int32_t PCMFile::Read10MsData(AudioFrame& audio_frame) {
uint16_t channels = 1;
if (read_stereo_) {
channels = 2;
}
int32_t payload_size = (int32_t) fread(audio_frame.data_, sizeof(uint16_t),
samples_10ms_ * channels, pcm_file_);
if (payload_size < samples_10ms_ * channels) {
for (int k = payload_size; k < samples_10ms_ * channels; k++) {
audio_frame.data_[k] = 0;
}
if (auto_rewind_) {
rewind(pcm_file_);
rewinded_ = true;
} else {
end_of_file_ = true;
}
}
audio_frame.samples_per_channel_ = samples_10ms_;
audio_frame.sample_rate_hz_ = frequency_;
audio_frame.num_channels_ = channels;
audio_frame.timestamp_ = timestamp_;
timestamp_ += samples_10ms_;
return samples_10ms_;
}
void PCMFile::Write10MsData(AudioFrame& audio_frame) {
if (audio_frame.num_channels_ == 1) {
if (!save_stereo_) {
if (fwrite(audio_frame.data_, sizeof(uint16_t),
audio_frame.samples_per_channel_, pcm_file_) !=
static_cast<size_t>(audio_frame.samples_per_channel_)) {
return;
}
} else {
int16_t* stereo_audio = new int16_t[2 * audio_frame.samples_per_channel_];
for (size_t k = 0; k < audio_frame.samples_per_channel_; k++) {
stereo_audio[k << 1] = audio_frame.data_[k];
stereo_audio[(k << 1) + 1] = audio_frame.data_[k];
}
if (fwrite(stereo_audio, sizeof(int16_t),
2 * audio_frame.samples_per_channel_, pcm_file_) !=
static_cast<size_t>(2 * audio_frame.samples_per_channel_)) {
return;
}
delete[] stereo_audio;
}
} else {
if (fwrite(audio_frame.data_, sizeof(int16_t),
audio_frame.num_channels_ * audio_frame.samples_per_channel_,
pcm_file_) !=
static_cast<size_t>(audio_frame.num_channels_ *
audio_frame.samples_per_channel_)) {
return;
}
}
}
void PCMFile::Write10MsData(int16_t* playout_buffer, size_t length_smpls) {
if (fwrite(playout_buffer, sizeof(uint16_t), length_smpls, pcm_file_) !=
length_smpls) {
return;
}
}
void PCMFile::Close() {
fclose(pcm_file_);
pcm_file_ = NULL;
}
void PCMFile::Rewind() {
rewind(pcm_file_);
end_of_file_ = false;
}
bool PCMFile::Rewinded() {
return rewinded_;
}
void PCMFile::SaveStereo(bool is_stereo) {
save_stereo_ = is_stereo;
}
void PCMFile::ReadStereo(bool is_stereo) {
read_stereo_ = is_stereo;
}
} // namespace webrtc

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_PCMFILE_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_PCMFILE_H_
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/typedefs.h"
namespace webrtc {
class PCMFile {
public:
PCMFile();
PCMFile(uint32_t timestamp);
~PCMFile() {
if (pcm_file_ != NULL) {
fclose(pcm_file_);
}
}
void Open(const std::string& filename, uint16_t frequency, const char* mode,
bool auto_rewind = false);
int32_t Read10MsData(AudioFrame& audio_frame);
void Write10MsData(int16_t *playout_buffer, size_t length_smpls);
void Write10MsData(AudioFrame& audio_frame);
uint16_t PayloadLength10Ms() const;
int32_t SamplingFrequency() const;
void Close();
bool EndOfFile() const {
return end_of_file_;
}
void Rewind();
static int16_t ChooseFile(std::string* file_name, int16_t max_len,
uint16_t* frequency_hz);
bool Rewinded();
void SaveStereo(bool is_stereo = true);
void ReadStereo(bool is_stereo = true);
private:
FILE* pcm_file_;
uint16_t samples_10ms_;
int32_t frequency_;
bool end_of_file_;
bool auto_rewind_;
bool rewinded_;
uint32_t timestamp_;
bool read_stereo_;
bool save_stereo_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_PCMFILE_H_

View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_coding/test/PacketLossTest.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/common.h"
#include "webrtc/test/testsupport/fileutils.h"
namespace webrtc {
ReceiverWithPacketLoss::ReceiverWithPacketLoss()
: loss_rate_(0),
burst_length_(1),
packet_counter_(0),
lost_packet_counter_(0),
burst_lost_counter_(burst_length_) {
}
void ReceiverWithPacketLoss::Setup(AudioCodingModule *acm,
RTPStream *rtpStream,
std::string out_file_name,
int channels,
int loss_rate,
int burst_length) {
loss_rate_ = loss_rate;
burst_length_ = burst_length;
burst_lost_counter_ = burst_length_; // To prevent first packet gets lost.
std::stringstream ss;
ss << out_file_name << "_" << loss_rate_ << "_" << burst_length_ << "_";
Receiver::Setup(acm, rtpStream, ss.str(), channels);
}
bool ReceiverWithPacketLoss::IncomingPacket() {
if (!_rtpStream->EndOfFile()) {
if (packet_counter_ == 0) {
_realPayloadSizeBytes = _rtpStream->Read(&_rtpInfo, _incomingPayload,
_payloadSizeBytes, &_nextTime);
if (_realPayloadSizeBytes == 0) {
if (_rtpStream->EndOfFile()) {
packet_counter_ = 0;
return true;
} else {
return false;
}
}
}
if (!PacketLost()) {
_acm->IncomingPacket(_incomingPayload, _realPayloadSizeBytes, _rtpInfo);
}
packet_counter_++;
_realPayloadSizeBytes = _rtpStream->Read(&_rtpInfo, _incomingPayload,
_payloadSizeBytes, &_nextTime);
if (_realPayloadSizeBytes == 0 && _rtpStream->EndOfFile()) {
packet_counter_ = 0;
lost_packet_counter_ = 0;
}
}
return true;
}
bool ReceiverWithPacketLoss::PacketLost() {
if (burst_lost_counter_ < burst_length_) {
lost_packet_counter_++;
burst_lost_counter_++;
return true;
}
if (lost_packet_counter_ * 100 < loss_rate_ * packet_counter_) {
lost_packet_counter_++;
burst_lost_counter_ = 1;
return true;
}
return false;
}
SenderWithFEC::SenderWithFEC()
: expected_loss_rate_(0) {
}
void SenderWithFEC::Setup(AudioCodingModule *acm, RTPStream *rtpStream,
std::string in_file_name, int sample_rate,
int channels, int expected_loss_rate) {
Sender::Setup(acm, rtpStream, in_file_name, sample_rate, channels);
EXPECT_TRUE(SetFEC(true));
EXPECT_TRUE(SetPacketLossRate(expected_loss_rate));
}
bool SenderWithFEC::SetFEC(bool enable_fec) {
if (_acm->SetCodecFEC(enable_fec) == 0) {
return true;
}
return false;
}
bool SenderWithFEC::SetPacketLossRate(int expected_loss_rate) {
if (_acm->SetPacketLossRate(expected_loss_rate) == 0) {
expected_loss_rate_ = expected_loss_rate;
return true;
}
return false;
}
PacketLossTest::PacketLossTest(int channels, int expected_loss_rate,
int actual_loss_rate, int burst_length)
: channels_(channels),
in_file_name_(channels_ == 1 ? "audio_coding/testfile32kHz" :
"audio_coding/teststereo32kHz"),
sample_rate_hz_(32000),
sender_(new SenderWithFEC),
receiver_(new ReceiverWithPacketLoss),
expected_loss_rate_(expected_loss_rate),
actual_loss_rate_(actual_loss_rate),
burst_length_(burst_length) {
}
void PacketLossTest::Perform() {
#ifndef WEBRTC_CODEC_OPUS
return;
#else
rtc::scoped_ptr<AudioCodingModule> acm(AudioCodingModule::Create(0));
int codec_id = acm->Codec("opus", 48000, channels_);
RTPFile rtpFile;
std::string fileName = webrtc::test::TempFilename(webrtc::test::OutputPath(),
"packet_loss_test");
// Encode to file
rtpFile.Open(fileName.c_str(), "wb+");
rtpFile.WriteHeader();
sender_->testMode = 0;
sender_->codeId = codec_id;
sender_->Setup(acm.get(), &rtpFile, in_file_name_, sample_rate_hz_, channels_,
expected_loss_rate_);
if (acm->SendCodec()) {
sender_->Run();
}
sender_->Teardown();
rtpFile.Close();
// Decode to file
rtpFile.Open(fileName.c_str(), "rb");
rtpFile.ReadHeader();
receiver_->testMode = 0;
receiver_->codeId = codec_id;
receiver_->Setup(acm.get(), &rtpFile, "packetLoss_out", channels_,
actual_loss_rate_, burst_length_);
receiver_->Run();
receiver_->Teardown();
rtpFile.Close();
#endif
}
} // namespace webrtc

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_PACKETLOSSTEST_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_PACKETLOSSTEST_H_
#include <string>
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/audio_coding/test/EncodeDecodeTest.h"
namespace webrtc {
class ReceiverWithPacketLoss : public Receiver {
public:
ReceiverWithPacketLoss();
void Setup(AudioCodingModule *acm, RTPStream *rtpStream,
std::string out_file_name, int channels, int loss_rate,
int burst_length);
bool IncomingPacket() override;
protected:
bool PacketLost();
int loss_rate_;
int burst_length_;
int packet_counter_;
int lost_packet_counter_;
int burst_lost_counter_;
};
class SenderWithFEC : public Sender {
public:
SenderWithFEC();
void Setup(AudioCodingModule *acm, RTPStream *rtpStream,
std::string in_file_name, int sample_rate, int channels,
int expected_loss_rate);
bool SetPacketLossRate(int expected_loss_rate);
bool SetFEC(bool enable_fec);
protected:
int expected_loss_rate_;
};
class PacketLossTest : public ACMTest {
public:
PacketLossTest(int channels, int expected_loss_rate_, int actual_loss_rate,
int burst_length);
void Perform();
protected:
int channels_;
std::string in_file_name_;
int sample_rate_hz_;
rtc::scoped_ptr<SenderWithFEC> sender_;
rtc::scoped_ptr<ReceiverWithPacketLoss> receiver_;
int expected_loss_rate_;
int actual_loss_rate_;
int burst_length_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_PACKETLOSSTEST_H_

View File

@ -0,0 +1,227 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "RTPFile.h"
#include <stdlib.h>
#include <limits>
#ifdef WIN32
# include <Winsock2.h>
#else
# include <arpa/inet.h>
#endif
#include "audio_coding_module.h"
#include "engine_configurations.h"
#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
// TODO(tlegrand): Consider removing usage of gtest.
#include "testing/gtest/include/gtest/gtest.h"
namespace webrtc {
void RTPStream::ParseRTPHeader(WebRtcRTPHeader* rtpInfo,
const uint8_t* rtpHeader) {
rtpInfo->header.payloadType = rtpHeader[1];
rtpInfo->header.sequenceNumber = (static_cast<uint16_t>(rtpHeader[2]) << 8) |
rtpHeader[3];
rtpInfo->header.timestamp = (static_cast<uint32_t>(rtpHeader[4]) << 24) |
(static_cast<uint32_t>(rtpHeader[5]) << 16) |
(static_cast<uint32_t>(rtpHeader[6]) << 8) | rtpHeader[7];
rtpInfo->header.ssrc = (static_cast<uint32_t>(rtpHeader[8]) << 24) |
(static_cast<uint32_t>(rtpHeader[9]) << 16) |
(static_cast<uint32_t>(rtpHeader[10]) << 8) | rtpHeader[11];
}
void RTPStream::MakeRTPheader(uint8_t* rtpHeader, uint8_t payloadType,
int16_t seqNo, uint32_t timeStamp,
uint32_t ssrc) {
rtpHeader[0] = 0x80;
rtpHeader[1] = payloadType;
rtpHeader[2] = (seqNo >> 8) & 0xFF;
rtpHeader[3] = seqNo & 0xFF;
rtpHeader[4] = timeStamp >> 24;
rtpHeader[5] = (timeStamp >> 16) & 0xFF;
rtpHeader[6] = (timeStamp >> 8) & 0xFF;
rtpHeader[7] = timeStamp & 0xFF;
rtpHeader[8] = ssrc >> 24;
rtpHeader[9] = (ssrc >> 16) & 0xFF;
rtpHeader[10] = (ssrc >> 8) & 0xFF;
rtpHeader[11] = ssrc & 0xFF;
}
RTPPacket::RTPPacket(uint8_t payloadType, uint32_t timeStamp, int16_t seqNo,
const uint8_t* payloadData, size_t payloadSize,
uint32_t frequency)
: payloadType(payloadType),
timeStamp(timeStamp),
seqNo(seqNo),
payloadSize(payloadSize),
frequency(frequency) {
if (payloadSize > 0) {
this->payloadData = new uint8_t[payloadSize];
memcpy(this->payloadData, payloadData, payloadSize);
}
}
RTPPacket::~RTPPacket() {
delete[] payloadData;
}
RTPBuffer::RTPBuffer() {
_queueRWLock = RWLockWrapper::CreateRWLock();
}
RTPBuffer::~RTPBuffer() {
delete _queueRWLock;
}
void RTPBuffer::Write(const uint8_t payloadType, const uint32_t timeStamp,
const int16_t seqNo, const uint8_t* payloadData,
const size_t payloadSize, uint32_t frequency) {
RTPPacket *packet = new RTPPacket(payloadType, timeStamp, seqNo, payloadData,
payloadSize, frequency);
_queueRWLock->AcquireLockExclusive();
_rtpQueue.push(packet);
_queueRWLock->ReleaseLockExclusive();
}
size_t RTPBuffer::Read(WebRtcRTPHeader* rtpInfo, uint8_t* payloadData,
size_t payloadSize, uint32_t* offset) {
_queueRWLock->AcquireLockShared();
RTPPacket *packet = _rtpQueue.front();
_rtpQueue.pop();
_queueRWLock->ReleaseLockShared();
rtpInfo->header.markerBit = 1;
rtpInfo->header.payloadType = packet->payloadType;
rtpInfo->header.sequenceNumber = packet->seqNo;
rtpInfo->header.ssrc = 0;
rtpInfo->header.timestamp = packet->timeStamp;
if (packet->payloadSize > 0 && payloadSize >= packet->payloadSize) {
memcpy(payloadData, packet->payloadData, packet->payloadSize);
} else {
return 0;
}
*offset = (packet->timeStamp / (packet->frequency / 1000));
return packet->payloadSize;
}
bool RTPBuffer::EndOfFile() const {
_queueRWLock->AcquireLockShared();
bool eof = _rtpQueue.empty();
_queueRWLock->ReleaseLockShared();
return eof;
}
void RTPFile::Open(const char *filename, const char *mode) {
if ((_rtpFile = fopen(filename, mode)) == NULL) {
printf("Cannot write file %s.\n", filename);
ADD_FAILURE() << "Unable to write file";
exit(1);
}
}
void RTPFile::Close() {
if (_rtpFile != NULL) {
fclose(_rtpFile);
_rtpFile = NULL;
}
}
void RTPFile::WriteHeader() {
// Write data in a format that NetEQ and RTP Play can parse
fprintf(_rtpFile, "#!RTPencode%s\n", "1.0");
uint32_t dummy_variable = 0;
// should be converted to network endian format, but does not matter when 0
EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
EXPECT_EQ(1u, fwrite(&dummy_variable, 2, 1, _rtpFile));
EXPECT_EQ(1u, fwrite(&dummy_variable, 2, 1, _rtpFile));
fflush(_rtpFile);
}
void RTPFile::ReadHeader() {
uint32_t start_sec, start_usec, source;
uint16_t port, padding;
char fileHeader[40];
EXPECT_TRUE(fgets(fileHeader, 40, _rtpFile) != 0);
EXPECT_EQ(1u, fread(&start_sec, 4, 1, _rtpFile));
start_sec = ntohl(start_sec);
EXPECT_EQ(1u, fread(&start_usec, 4, 1, _rtpFile));
start_usec = ntohl(start_usec);
EXPECT_EQ(1u, fread(&source, 4, 1, _rtpFile));
source = ntohl(source);
EXPECT_EQ(1u, fread(&port, 2, 1, _rtpFile));
port = ntohs(port);
EXPECT_EQ(1u, fread(&padding, 2, 1, _rtpFile));
padding = ntohs(padding);
}
void RTPFile::Write(const uint8_t payloadType, const uint32_t timeStamp,
const int16_t seqNo, const uint8_t* payloadData,
const size_t payloadSize, uint32_t frequency) {
/* write RTP packet to file */
uint8_t rtpHeader[12];
MakeRTPheader(rtpHeader, payloadType, seqNo, timeStamp, 0);
ASSERT_LE(12 + payloadSize + 8, std::numeric_limits<u_short>::max());
uint16_t lengthBytes = htons(static_cast<u_short>(12 + payloadSize + 8));
uint16_t plen = htons(static_cast<u_short>(12 + payloadSize));
uint32_t offsetMs;
offsetMs = (timeStamp / (frequency / 1000));
offsetMs = htonl(offsetMs);
EXPECT_EQ(1u, fwrite(&lengthBytes, 2, 1, _rtpFile));
EXPECT_EQ(1u, fwrite(&plen, 2, 1, _rtpFile));
EXPECT_EQ(1u, fwrite(&offsetMs, 4, 1, _rtpFile));
EXPECT_EQ(1u, fwrite(&rtpHeader, 12, 1, _rtpFile));
EXPECT_EQ(payloadSize, fwrite(payloadData, 1, payloadSize, _rtpFile));
}
size_t RTPFile::Read(WebRtcRTPHeader* rtpInfo, uint8_t* payloadData,
size_t payloadSize, uint32_t* offset) {
uint16_t lengthBytes;
uint16_t plen;
uint8_t rtpHeader[12];
size_t read_len = fread(&lengthBytes, 2, 1, _rtpFile);
/* Check if we have reached end of file. */
if ((read_len == 0) && feof(_rtpFile)) {
_rtpEOF = true;
return 0;
}
EXPECT_EQ(1u, fread(&plen, 2, 1, _rtpFile));
EXPECT_EQ(1u, fread(offset, 4, 1, _rtpFile));
lengthBytes = ntohs(lengthBytes);
plen = ntohs(plen);
*offset = ntohl(*offset);
EXPECT_GT(plen, 11);
EXPECT_EQ(1u, fread(rtpHeader, 12, 1, _rtpFile));
ParseRTPHeader(rtpInfo, rtpHeader);
rtpInfo->type.Audio.isCNG = false;
rtpInfo->type.Audio.channel = 1;
EXPECT_EQ(lengthBytes, plen + 8);
if (plen == 0) {
return 0;
}
if (lengthBytes < 20) {
return 0;
}
if (payloadSize < static_cast<size_t>((lengthBytes - 20))) {
return 0;
}
lengthBytes -= 20;
EXPECT_EQ(lengthBytes, fread(payloadData, 1, lengthBytes, _rtpFile));
return lengthBytes;
}
} // namespace webrtc

View File

@ -0,0 +1,126 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_RTPFILE_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_RTPFILE_H_
#include <stdio.h>
#include <queue>
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
#include "webrtc/typedefs.h"
namespace webrtc {
class RTPStream {
public:
virtual ~RTPStream() {
}
virtual void Write(const uint8_t payloadType, const uint32_t timeStamp,
const int16_t seqNo, const uint8_t* payloadData,
const size_t payloadSize, uint32_t frequency) = 0;
// Returns the packet's payload size. Zero should be treated as an
// end-of-stream (in the case that EndOfFile() is true) or an error.
virtual size_t Read(WebRtcRTPHeader* rtpInfo, uint8_t* payloadData,
size_t payloadSize, uint32_t* offset) = 0;
virtual bool EndOfFile() const = 0;
protected:
void MakeRTPheader(uint8_t* rtpHeader, uint8_t payloadType, int16_t seqNo,
uint32_t timeStamp, uint32_t ssrc);
void ParseRTPHeader(WebRtcRTPHeader* rtpInfo, const uint8_t* rtpHeader);
};
class RTPPacket {
public:
RTPPacket(uint8_t payloadType, uint32_t timeStamp, int16_t seqNo,
const uint8_t* payloadData, size_t payloadSize,
uint32_t frequency);
~RTPPacket();
uint8_t payloadType;
uint32_t timeStamp;
int16_t seqNo;
uint8_t* payloadData;
size_t payloadSize;
uint32_t frequency;
};
class RTPBuffer : public RTPStream {
public:
RTPBuffer();
~RTPBuffer();
void Write(const uint8_t payloadType,
const uint32_t timeStamp,
const int16_t seqNo,
const uint8_t* payloadData,
const size_t payloadSize,
uint32_t frequency) override;
size_t Read(WebRtcRTPHeader* rtpInfo,
uint8_t* payloadData,
size_t payloadSize,
uint32_t* offset) override;
bool EndOfFile() const override;
private:
RWLockWrapper* _queueRWLock;
std::queue<RTPPacket *> _rtpQueue;
};
class RTPFile : public RTPStream {
public:
~RTPFile() {
}
RTPFile()
: _rtpFile(NULL),
_rtpEOF(false) {
}
void Open(const char *outFilename, const char *mode);
void Close();
void WriteHeader();
void ReadHeader();
void Write(const uint8_t payloadType,
const uint32_t timeStamp,
const int16_t seqNo,
const uint8_t* payloadData,
const size_t payloadSize,
uint32_t frequency) override;
size_t Read(WebRtcRTPHeader* rtpInfo,
uint8_t* payloadData,
size_t payloadSize,
uint32_t* offset) override;
bool EndOfFile() const override { return _rtpEOF; }
private:
FILE* _rtpFile;
bool _rtpEOF;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_RTPFILE_H_

View File

@ -0,0 +1,196 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/test/SpatialAudio.h"
#include "webrtc/system_wrappers/include/trace.h"
#include "webrtc/system_wrappers/include/trace.h"
#include "webrtc/test/testsupport/fileutils.h"
namespace webrtc {
#define NUM_PANN_COEFFS 10
SpatialAudio::SpatialAudio(int testMode)
: _acmLeft(AudioCodingModule::Create(1)),
_acmRight(AudioCodingModule::Create(2)),
_acmReceiver(AudioCodingModule::Create(3)),
_testMode(testMode) {
}
SpatialAudio::~SpatialAudio() {
delete _channel;
_inFile.Close();
_outFile.Close();
}
int16_t SpatialAudio::Setup() {
_channel = new Channel;
// Register callback for the sender side.
CHECK_ERROR(_acmLeft->RegisterTransportCallback(_channel));
CHECK_ERROR(_acmRight->RegisterTransportCallback(_channel));
// Register the receiver ACM in channel
_channel->RegisterReceiverACM(_acmReceiver.get());
uint16_t sampFreqHz = 32000;
const std::string file_name = webrtc::test::ResourcePath(
"audio_coding/testfile32kHz", "pcm");
_inFile.Open(file_name, sampFreqHz, "rb", false);
std::string output_file = webrtc::test::OutputPath()
+ "out_spatial_autotest.pcm";
if (_testMode == 1) {
output_file = webrtc::test::OutputPath() + "testspatial_out.pcm";
printf("\n");
printf("Enter the output file [%s]: ", output_file.c_str());
PCMFile::ChooseFile(&output_file, MAX_FILE_NAME_LENGTH_BYTE, &sampFreqHz);
} else {
output_file = webrtc::test::OutputPath() + "testspatial_out.pcm";
}
_outFile.Open(output_file, sampFreqHz, "wb", false);
_outFile.SaveStereo(true);
// Register all available codes as receiving codecs.
CodecInst codecInst;
int status;
uint8_t num_encoders = _acmReceiver->NumberOfCodecs();
// Register all available codes as receiving codecs once more.
for (uint8_t n = 0; n < num_encoders; n++) {
status = _acmReceiver->Codec(n, &codecInst);
if (status < 0) {
printf("Error in Codec(), no matching codec found");
}
status = _acmReceiver->RegisterReceiveCodec(codecInst);
if (status < 0) {
printf("Error in RegisterReceiveCodec() for payload type %d",
codecInst.pltype);
}
}
return 0;
}
void SpatialAudio::Perform() {
if (_testMode == 0) {
printf("Running SpatialAudio Test");
WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceAudioCoding, -1,
"---------- SpatialAudio ----------");
}
Setup();
CodecInst codecInst;
_acmLeft->Codec((uint8_t) 1, &codecInst);
CHECK_ERROR(_acmLeft->RegisterSendCodec(codecInst));
EncodeDecode();
int16_t pannCntr = 0;
double leftPanning[NUM_PANN_COEFFS] = { 1.00, 0.95, 0.90, 0.85, 0.80, 0.75,
0.70, 0.60, 0.55, 0.50 };
double rightPanning[NUM_PANN_COEFFS] = { 0.50, 0.55, 0.60, 0.70, 0.75, 0.80,
0.85, 0.90, 0.95, 1.00 };
while ((pannCntr + 1) < NUM_PANN_COEFFS) {
_acmLeft->Codec((uint8_t) 0, &codecInst);
codecInst.pacsize = 480;
CHECK_ERROR(_acmLeft->RegisterSendCodec(codecInst));
CHECK_ERROR(_acmRight->RegisterSendCodec(codecInst));
EncodeDecode(leftPanning[pannCntr], rightPanning[pannCntr]);
pannCntr++;
// Change codec
_acmLeft->Codec((uint8_t) 3, &codecInst);
codecInst.pacsize = 320;
CHECK_ERROR(_acmLeft->RegisterSendCodec(codecInst));
CHECK_ERROR(_acmRight->RegisterSendCodec(codecInst));
EncodeDecode(leftPanning[pannCntr], rightPanning[pannCntr]);
pannCntr++;
if (_testMode == 0) {
printf(".");
}
}
_acmLeft->Codec((uint8_t) 4, &codecInst);
CHECK_ERROR(_acmLeft->RegisterSendCodec(codecInst));
EncodeDecode();
_acmLeft->Codec((uint8_t) 0, &codecInst);
codecInst.pacsize = 480;
CHECK_ERROR(_acmLeft->RegisterSendCodec(codecInst));
CHECK_ERROR(_acmRight->RegisterSendCodec(codecInst));
pannCntr = NUM_PANN_COEFFS - 1;
while (pannCntr >= 0) {
EncodeDecode(leftPanning[pannCntr], rightPanning[pannCntr]);
pannCntr--;
if (_testMode == 0) {
printf(".");
}
}
if (_testMode == 0) {
printf("Done!\n");
}
}
void SpatialAudio::EncodeDecode(const double leftPanning,
const double rightPanning) {
AudioFrame audioFrame;
int32_t outFileSampFreq = _outFile.SamplingFrequency();
const double rightToLeftRatio = rightPanning / leftPanning;
_channel->SetIsStereo(true);
while (!_inFile.EndOfFile()) {
_inFile.Read10MsData(audioFrame);
for (size_t n = 0; n < audioFrame.samples_per_channel_; n++) {
audioFrame.data_[n] = (int16_t) floor(
audioFrame.data_[n] * leftPanning + 0.5);
}
CHECK_ERROR(_acmLeft->Add10MsData(audioFrame));
for (size_t n = 0; n < audioFrame.samples_per_channel_; n++) {
audioFrame.data_[n] = (int16_t) floor(
audioFrame.data_[n] * rightToLeftRatio + 0.5);
}
CHECK_ERROR(_acmRight->Add10MsData(audioFrame));
CHECK_ERROR(_acmReceiver->PlayoutData10Ms(outFileSampFreq, &audioFrame));
_outFile.Write10MsData(audioFrame);
}
_inFile.Rewind();
}
void SpatialAudio::EncodeDecode() {
AudioFrame audioFrame;
int32_t outFileSampFreq = _outFile.SamplingFrequency();
_channel->SetIsStereo(false);
while (!_inFile.EndOfFile()) {
_inFile.Read10MsData(audioFrame);
CHECK_ERROR(_acmLeft->Add10MsData(audioFrame));
CHECK_ERROR(_acmReceiver->PlayoutData10Ms(outFileSampFreq, &audioFrame));
_outFile.Write10MsData(audioFrame);
}
_inFile.Rewind();
}
} // namespace webrtc

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_SPATIALAUDIO_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_SPATIALAUDIO_H_
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/audio_coding/test/ACMTest.h"
#include "webrtc/modules/audio_coding/test/Channel.h"
#include "webrtc/modules/audio_coding/test/PCMFile.h"
#include "webrtc/modules/audio_coding/test/utility.h"
#define MAX_FILE_NAME_LENGTH_BYTE 500
namespace webrtc {
class SpatialAudio : public ACMTest {
public:
SpatialAudio(int testMode);
~SpatialAudio();
void Perform();
private:
int16_t Setup();
void EncodeDecode(double leftPanning, double rightPanning);
void EncodeDecode();
rtc::scoped_ptr<AudioCodingModule> _acmLeft;
rtc::scoped_ptr<AudioCodingModule> _acmRight;
rtc::scoped_ptr<AudioCodingModule> _acmReceiver;
Channel* _channel;
PCMFile _inFile;
PCMFile _outFile;
int _testMode;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_SPATIALAUDIO_H_

View File

@ -0,0 +1,485 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_coding/test/TestAllCodecs.h"
#include <cstdio>
#include <limits>
#include <string>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/common_types.h"
#include "webrtc/engine_configurations.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h"
#include "webrtc/modules/audio_coding/test/utility.h"
#include "webrtc/system_wrappers/include/trace.h"
#include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/typedefs.h"
// Description of the test:
// In this test we set up a one-way communication channel from a participant
// called "a" to a participant called "b".
// a -> channel_a_to_b -> b
//
// The test loops through all available mono codecs, encode at "a" sends over
// the channel, and decodes at "b".
namespace {
const size_t kVariableSize = std::numeric_limits<size_t>::max();
}
namespace webrtc {
// Class for simulating packet handling.
TestPack::TestPack()
: receiver_acm_(NULL),
sequence_number_(0),
timestamp_diff_(0),
last_in_timestamp_(0),
total_bytes_(0),
payload_size_(0) {
}
TestPack::~TestPack() {
}
void TestPack::RegisterReceiverACM(AudioCodingModule* acm) {
receiver_acm_ = acm;
return;
}
int32_t TestPack::SendData(FrameType frame_type, uint8_t payload_type,
uint32_t timestamp, const uint8_t* payload_data,
size_t payload_size,
const RTPFragmentationHeader* fragmentation) {
WebRtcRTPHeader rtp_info;
int32_t status;
rtp_info.header.markerBit = false;
rtp_info.header.ssrc = 0;
rtp_info.header.sequenceNumber = sequence_number_++;
rtp_info.header.payloadType = payload_type;
rtp_info.header.timestamp = timestamp;
if (frame_type == kAudioFrameCN) {
rtp_info.type.Audio.isCNG = true;
} else {
rtp_info.type.Audio.isCNG = false;
}
if (frame_type == kEmptyFrame) {
// Skip this frame.
return 0;
}
// Only run mono for all test cases.
rtp_info.type.Audio.channel = 1;
memcpy(payload_data_, payload_data, payload_size);
status = receiver_acm_->IncomingPacket(payload_data_, payload_size, rtp_info);
payload_size_ = payload_size;
timestamp_diff_ = timestamp - last_in_timestamp_;
last_in_timestamp_ = timestamp;
total_bytes_ += payload_size;
return status;
}
size_t TestPack::payload_size() {
return payload_size_;
}
uint32_t TestPack::timestamp_diff() {
return timestamp_diff_;
}
void TestPack::reset_payload_size() {
payload_size_ = 0;
}
TestAllCodecs::TestAllCodecs(int test_mode)
: acm_a_(AudioCodingModule::Create(0)),
acm_b_(AudioCodingModule::Create(1)),
channel_a_to_b_(NULL),
test_count_(0),
packet_size_samples_(0),
packet_size_bytes_(0) {
// test_mode = 0 for silent test (auto test)
test_mode_ = test_mode;
}
TestAllCodecs::~TestAllCodecs() {
if (channel_a_to_b_ != NULL) {
delete channel_a_to_b_;
channel_a_to_b_ = NULL;
}
}
void TestAllCodecs::Perform() {
const std::string file_name = webrtc::test::ResourcePath(
"audio_coding/testfile32kHz", "pcm");
infile_a_.Open(file_name, 32000, "rb");
if (test_mode_ == 0) {
WEBRTC_TRACE(kTraceStateInfo, kTraceAudioCoding, -1,
"---------- TestAllCodecs ----------");
}
acm_a_->InitializeReceiver();
acm_b_->InitializeReceiver();
uint8_t num_encoders = acm_a_->NumberOfCodecs();
CodecInst my_codec_param;
for (uint8_t n = 0; n < num_encoders; n++) {
acm_b_->Codec(n, &my_codec_param);
if (!strcmp(my_codec_param.plname, "opus")) {
my_codec_param.channels = 1;
}
acm_b_->RegisterReceiveCodec(my_codec_param);
}
// Create and connect the channel
channel_a_to_b_ = new TestPack;
acm_a_->RegisterTransportCallback(channel_a_to_b_);
channel_a_to_b_->RegisterReceiverACM(acm_b_.get());
// All codecs are tested for all allowed sampling frequencies, rates and
// packet sizes.
#ifdef WEBRTC_CODEC_G722
if (test_mode_ != 0) {
printf("===============================================================\n");
}
test_count_++;
OpenOutFile(test_count_);
char codec_g722[] = "G722";
RegisterSendCodec('A', codec_g722, 16000, 64000, 160, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_g722, 16000, 64000, 320, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_g722, 16000, 64000, 480, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_g722, 16000, 64000, 640, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_g722, 16000, 64000, 800, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_g722, 16000, 64000, 960, 0);
Run(channel_a_to_b_);
outfile_b_.Close();
#endif
#ifdef WEBRTC_CODEC_ILBC
if (test_mode_ != 0) {
printf("===============================================================\n");
}
test_count_++;
OpenOutFile(test_count_);
char codec_ilbc[] = "ILBC";
RegisterSendCodec('A', codec_ilbc, 8000, 13300, 240, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_ilbc, 8000, 13300, 480, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_ilbc, 8000, 15200, 160, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_ilbc, 8000, 15200, 320, 0);
Run(channel_a_to_b_);
outfile_b_.Close();
#endif
#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
if (test_mode_ != 0) {
printf("===============================================================\n");
}
test_count_++;
OpenOutFile(test_count_);
char codec_isac[] = "ISAC";
RegisterSendCodec('A', codec_isac, 16000, -1, 480, kVariableSize);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_isac, 16000, -1, 960, kVariableSize);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_isac, 16000, 15000, 480, kVariableSize);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_isac, 16000, 32000, 960, kVariableSize);
Run(channel_a_to_b_);
outfile_b_.Close();
#endif
#ifdef WEBRTC_CODEC_ISAC
if (test_mode_ != 0) {
printf("===============================================================\n");
}
test_count_++;
OpenOutFile(test_count_);
RegisterSendCodec('A', codec_isac, 32000, -1, 960, kVariableSize);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_isac, 32000, 56000, 960, kVariableSize);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_isac, 32000, 37000, 960, kVariableSize);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_isac, 32000, 32000, 960, kVariableSize);
Run(channel_a_to_b_);
outfile_b_.Close();
#endif
if (test_mode_ != 0) {
printf("===============================================================\n");
}
test_count_++;
OpenOutFile(test_count_);
char codec_l16[] = "L16";
RegisterSendCodec('A', codec_l16, 8000, 128000, 80, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_l16, 8000, 128000, 160, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_l16, 8000, 128000, 240, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_l16, 8000, 128000, 320, 0);
Run(channel_a_to_b_);
outfile_b_.Close();
if (test_mode_ != 0) {
printf("===============================================================\n");
}
test_count_++;
OpenOutFile(test_count_);
RegisterSendCodec('A', codec_l16, 16000, 256000, 160, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_l16, 16000, 256000, 320, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_l16, 16000, 256000, 480, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_l16, 16000, 256000, 640, 0);
Run(channel_a_to_b_);
outfile_b_.Close();
if (test_mode_ != 0) {
printf("===============================================================\n");
}
test_count_++;
OpenOutFile(test_count_);
RegisterSendCodec('A', codec_l16, 32000, 512000, 320, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_l16, 32000, 512000, 640, 0);
Run(channel_a_to_b_);
outfile_b_.Close();
if (test_mode_ != 0) {
printf("===============================================================\n");
}
test_count_++;
OpenOutFile(test_count_);
char codec_pcma[] = "PCMA";
RegisterSendCodec('A', codec_pcma, 8000, 64000, 80, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_pcma, 8000, 64000, 160, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_pcma, 8000, 64000, 240, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_pcma, 8000, 64000, 320, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_pcma, 8000, 64000, 400, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_pcma, 8000, 64000, 480, 0);
Run(channel_a_to_b_);
if (test_mode_ != 0) {
printf("===============================================================\n");
}
char codec_pcmu[] = "PCMU";
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 80, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 160, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 240, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 320, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 400, 0);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 480, 0);
Run(channel_a_to_b_);
outfile_b_.Close();
#ifdef WEBRTC_CODEC_OPUS
if (test_mode_ != 0) {
printf("===============================================================\n");
}
test_count_++;
OpenOutFile(test_count_);
char codec_opus[] = "OPUS";
RegisterSendCodec('A', codec_opus, 48000, 6000, 480, kVariableSize);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_opus, 48000, 20000, 480*2, kVariableSize);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_opus, 48000, 32000, 480*4, kVariableSize);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_opus, 48000, 48000, 480, kVariableSize);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_opus, 48000, 64000, 480*4, kVariableSize);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_opus, 48000, 96000, 480*6, kVariableSize);
Run(channel_a_to_b_);
RegisterSendCodec('A', codec_opus, 48000, 500000, 480*2, kVariableSize);
Run(channel_a_to_b_);
outfile_b_.Close();
#endif
if (test_mode_ != 0) {
printf("===============================================================\n");
/* Print out all codecs that were not tested in the run */
printf("The following codecs was not included in the test:\n");
#ifndef WEBRTC_CODEC_G722
printf(" G.722\n");
#endif
#ifndef WEBRTC_CODEC_ILBC
printf(" iLBC\n");
#endif
#ifndef WEBRTC_CODEC_ISAC
printf(" ISAC float\n");
#endif
#ifndef WEBRTC_CODEC_ISACFX
printf(" ISAC fix\n");
#endif
printf("\nTo complete the test, listen to the %d number of output files.\n",
test_count_);
}
}
// Register Codec to use in the test
//
// Input: side - which ACM to use, 'A' or 'B'
// codec_name - name to use when register the codec
// sampling_freq_hz - sampling frequency in Herz
// rate - bitrate in bytes
// packet_size - packet size in samples
// extra_byte - if extra bytes needed compared to the bitrate
// used when registering, can be an internal header
// set to kVariableSize if the codec is a variable
// rate codec
void TestAllCodecs::RegisterSendCodec(char side, char* codec_name,
int32_t sampling_freq_hz, int rate,
int packet_size, size_t extra_byte) {
if (test_mode_ != 0) {
// Print out codec and settings.
printf("codec: %s Freq: %d Rate: %d PackSize: %d\n", codec_name,
sampling_freq_hz, rate, packet_size);
}
// Store packet-size in samples, used to validate the received packet.
// If G.722, store half the size to compensate for the timestamp bug in the
// RFC for G.722.
// If iSAC runs in adaptive mode, packet size in samples can change on the
// fly, so we exclude this test by setting |packet_size_samples_| to -1.
if (!strcmp(codec_name, "G722")) {
packet_size_samples_ = packet_size / 2;
} else if (!strcmp(codec_name, "ISAC") && (rate == -1)) {
packet_size_samples_ = -1;
} else {
packet_size_samples_ = packet_size;
}
// Store the expected packet size in bytes, used to validate the received
// packet. If variable rate codec (extra_byte == -1), set to -1.
if (extra_byte != kVariableSize) {
// Add 0.875 to always round up to a whole byte
packet_size_bytes_ = static_cast<size_t>(
static_cast<float>(packet_size * rate) /
static_cast<float>(sampling_freq_hz * 8) + 0.875) + extra_byte;
} else {
// Packets will have a variable size.
packet_size_bytes_ = kVariableSize;
}
// Set pointer to the ACM where to register the codec.
AudioCodingModule* my_acm = NULL;
switch (side) {
case 'A': {
my_acm = acm_a_.get();
break;
}
case 'B': {
my_acm = acm_b_.get();
break;
}
default: {
break;
}
}
ASSERT_TRUE(my_acm != NULL);
// Get all codec parameters before registering
CodecInst my_codec_param;
CHECK_ERROR(AudioCodingModule::Codec(codec_name, &my_codec_param,
sampling_freq_hz, 1));
my_codec_param.rate = rate;
my_codec_param.pacsize = packet_size;
CHECK_ERROR(my_acm->RegisterSendCodec(my_codec_param));
}
void TestAllCodecs::Run(TestPack* channel) {
AudioFrame audio_frame;
int32_t out_freq_hz = outfile_b_.SamplingFrequency();
size_t receive_size;
uint32_t timestamp_diff;
channel->reset_payload_size();
int error_count = 0;
int counter = 0;
while (!infile_a_.EndOfFile()) {
// Add 10 msec to ACM.
infile_a_.Read10MsData(audio_frame);
CHECK_ERROR(acm_a_->Add10MsData(audio_frame));
// Verify that the received packet size matches the settings.
receive_size = channel->payload_size();
if (receive_size) {
if ((receive_size != packet_size_bytes_) &&
(packet_size_bytes_ != kVariableSize)) {
error_count++;
}
// Verify that the timestamp is updated with expected length. The counter
// is used to avoid problems when switching codec or frame size in the
// test.
timestamp_diff = channel->timestamp_diff();
if ((counter > 10) &&
(static_cast<int>(timestamp_diff) != packet_size_samples_) &&
(packet_size_samples_ > -1))
error_count++;
}
// Run received side of ACM.
CHECK_ERROR(acm_b_->PlayoutData10Ms(out_freq_hz, &audio_frame));
// Write output speech to file.
outfile_b_.Write10MsData(audio_frame.data_,
audio_frame.samples_per_channel_);
// Update loop counter
counter++;
}
EXPECT_EQ(0, error_count);
if (infile_a_.EndOfFile()) {
infile_a_.Rewind();
}
}
void TestAllCodecs::OpenOutFile(int test_number) {
std::string filename = webrtc::test::OutputPath();
std::ostringstream test_number_str;
test_number_str << test_number;
filename += "testallcodecs_out_";
filename += test_number_str.str();
filename += ".pcm";
outfile_b_.Open(filename, 32000, "wb");
}
void TestAllCodecs::DisplaySendReceiveCodec() {
CodecInst my_codec_param;
printf("%s -> ", acm_a_->SendCodec()->plname);
acm_b_->ReceiveCodec(&my_codec_param);
printf("%s\n", my_codec_param.plname);
}
} // namespace webrtc

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_TESTALLCODECS_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_TESTALLCODECS_H_
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/audio_coding/test/ACMTest.h"
#include "webrtc/modules/audio_coding/test/Channel.h"
#include "webrtc/modules/audio_coding/test/PCMFile.h"
#include "webrtc/typedefs.h"
namespace webrtc {
class Config;
class TestPack : public AudioPacketizationCallback {
public:
TestPack();
~TestPack();
void RegisterReceiverACM(AudioCodingModule* acm);
int32_t SendData(FrameType frame_type,
uint8_t payload_type,
uint32_t timestamp,
const uint8_t* payload_data,
size_t payload_size,
const RTPFragmentationHeader* fragmentation) override;
size_t payload_size();
uint32_t timestamp_diff();
void reset_payload_size();
private:
AudioCodingModule* receiver_acm_;
uint16_t sequence_number_;
uint8_t payload_data_[60 * 32 * 2 * 2];
uint32_t timestamp_diff_;
uint32_t last_in_timestamp_;
uint64_t total_bytes_;
size_t payload_size_;
};
class TestAllCodecs : public ACMTest {
public:
explicit TestAllCodecs(int test_mode);
~TestAllCodecs();
void Perform() override;
private:
// The default value of '-1' indicates that the registration is based only on
// codec name, and a sampling frequency matching is not required.
// This is useful for codecs which support several sampling frequency.
// Note! Only mono mode is tested in this test.
void RegisterSendCodec(char side, char* codec_name, int32_t sampling_freq_hz,
int rate, int packet_size, size_t extra_byte);
void Run(TestPack* channel);
void OpenOutFile(int test_number);
void DisplaySendReceiveCodec();
int test_mode_;
rtc::scoped_ptr<AudioCodingModule> acm_a_;
rtc::scoped_ptr<AudioCodingModule> acm_b_;
TestPack* channel_a_to_b_;
PCMFile infile_a_;
PCMFile outfile_b_;
int test_count_;
int packet_size_samples_;
size_t packet_size_bytes_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_TESTALLCODECS_H_

View File

@ -0,0 +1,476 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_coding/test/TestRedFec.h"
#include <assert.h>
#include "webrtc/common.h"
#include "webrtc/common_types.h"
#include "webrtc/engine_configurations.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h"
#include "webrtc/modules/audio_coding/test/utility.h"
#include "webrtc/system_wrappers/include/trace.h"
#include "webrtc/test/testsupport/fileutils.h"
#ifdef SUPPORT_RED_WB
#undef SUPPORT_RED_WB
#endif
#ifdef SUPPORT_RED_SWB
#undef SUPPORT_RED_SWB
#endif
#ifdef SUPPORT_RED_FB
#undef SUPPORT_RED_FB
#endif
namespace webrtc {
namespace {
const char kNameL16[] = "L16";
const char kNamePCMU[] = "PCMU";
const char kNameCN[] = "CN";
const char kNameRED[] = "RED";
// These three are only used by code #ifdeffed on WEBRTC_CODEC_G722.
#ifdef WEBRTC_CODEC_G722
const char kNameISAC[] = "ISAC";
const char kNameG722[] = "G722";
const char kNameOPUS[] = "opus";
#endif
}
TestRedFec::TestRedFec()
: _acmA(AudioCodingModule::Create(0)),
_acmB(AudioCodingModule::Create(1)),
_channelA2B(NULL),
_testCntr(0) {
}
TestRedFec::~TestRedFec() {
if (_channelA2B != NULL) {
delete _channelA2B;
_channelA2B = NULL;
}
}
void TestRedFec::Perform() {
const std::string file_name = webrtc::test::ResourcePath(
"audio_coding/testfile32kHz", "pcm");
_inFileA.Open(file_name, 32000, "rb");
ASSERT_EQ(0, _acmA->InitializeReceiver());
ASSERT_EQ(0, _acmB->InitializeReceiver());
uint8_t numEncoders = _acmA->NumberOfCodecs();
CodecInst myCodecParam;
for (uint8_t n = 0; n < numEncoders; n++) {
EXPECT_EQ(0, _acmB->Codec(n, &myCodecParam));
// Default number of channels is 2 for opus, so we change to 1 in this test.
if (!strcmp(myCodecParam.plname, "opus")) {
myCodecParam.channels = 1;
}
EXPECT_EQ(0, _acmB->RegisterReceiveCodec(myCodecParam));
}
// Create and connect the channel
_channelA2B = new Channel;
_acmA->RegisterTransportCallback(_channelA2B);
_channelA2B->RegisterReceiverACM(_acmB.get());
EXPECT_EQ(0, RegisterSendCodec('A', kNameL16, 8000));
EXPECT_EQ(0, RegisterSendCodec('A', kNameCN, 8000));
EXPECT_EQ(0, RegisterSendCodec('A', kNameRED));
EXPECT_EQ(0, SetVAD(true, true, VADAggr));
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
OpenOutFile(_testCntr);
Run();
_outFileB.Close();
RegisterSendCodec('A', kNamePCMU, 8000);
// Switch to another 8 kHz codec, RED should remain switched on.
EXPECT_TRUE(_acmA->REDStatus());
OpenOutFile(_testCntr);
Run();
_outFileB.Close();
#ifndef WEBRTC_CODEC_G722
EXPECT_TRUE(false);
printf("G722 needs to be activated to run this test\n");
return;
#else
EXPECT_EQ(0, RegisterSendCodec('A', kNameG722, 16000));
EXPECT_EQ(0, RegisterSendCodec('A', kNameCN, 16000));
#ifdef SUPPORT_RED_WB
// Switch codec, RED should remain.
EXPECT_TRUE(_acmA->REDStatus());
#else
// Switch to a 16 kHz codec, RED should have been switched off.
EXPECT_FALSE(_acmA->REDStatus());
#endif
OpenOutFile(_testCntr);
EXPECT_EQ(0, SetVAD(true, true, VADAggr));
EXPECT_EQ(0, _acmA->SetREDStatus(false));
EXPECT_FALSE(_acmA->REDStatus());
Run();
#ifdef SUPPORT_RED_WB
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
#else
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
EXPECT_FALSE(_acmA->REDStatus());
#endif
Run();
_outFileB.Close();
RegisterSendCodec('A', kNameISAC, 16000);
#ifdef SUPPORT_RED_WB
// Switch codec, RED should remain.
EXPECT_TRUE(_acmA->REDStatus());
#else
EXPECT_FALSE(_acmA->REDStatus());
#endif
OpenOutFile(_testCntr);
EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
EXPECT_EQ(0, _acmA->SetREDStatus(false));
EXPECT_FALSE(_acmA->REDStatus());
Run();
_outFileB.Close();
#ifdef SUPPORT_RED_WB
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
#else
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
EXPECT_FALSE(_acmA->REDStatus());
#endif
OpenOutFile(_testCntr);
Run();
_outFileB.Close();
RegisterSendCodec('A', kNameISAC, 32000);
#if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB)
// Switch codec, RED should remain.
EXPECT_TRUE(_acmA->REDStatus());
#else
// Switch to a 32 kHz codec, RED should have been switched off.
EXPECT_FALSE(_acmA->REDStatus());
#endif
OpenOutFile(_testCntr);
EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
EXPECT_EQ(0, _acmA->SetREDStatus(false));
EXPECT_FALSE(_acmA->REDStatus());
Run();
_outFileB.Close();
#ifdef SUPPORT_RED_SWB
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
#else
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
EXPECT_FALSE(_acmA->REDStatus());
#endif
OpenOutFile(_testCntr);
Run();
_outFileB.Close();
RegisterSendCodec('A', kNameISAC, 32000);
EXPECT_EQ(0, SetVAD(false, false, VADNormal));
#if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB)
OpenOutFile(_testCntr);
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', kNameISAC, 16000);
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', kNameISAC, 32000);
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', kNameISAC, 16000);
EXPECT_TRUE(_acmA->REDStatus());
Run();
_outFileB.Close();
#else
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
EXPECT_FALSE(_acmA->REDStatus());
#endif
_channelA2B->SetFECTestWithPacketLoss(true);
// Following tests are under packet losses.
EXPECT_EQ(0, RegisterSendCodec('A', kNameG722));
EXPECT_EQ(0, RegisterSendCodec('A', kNameCN, 16000));
#if defined(SUPPORT_RED_WB) && defined(SUPPORT_RED_SWB)
// Switch codec, RED should remain.
EXPECT_TRUE(_acmA->REDStatus());
#else
// Switch to a 16 kHz codec, RED should have been switched off.
EXPECT_FALSE(_acmA->REDStatus());
#endif
OpenOutFile(_testCntr);
EXPECT_EQ(0, SetVAD(true, true, VADAggr));
EXPECT_EQ(0, _acmA->SetREDStatus(false));
EXPECT_FALSE(_acmA->REDStatus());
Run();
_outFileB.Close();
#ifdef SUPPORT_RED_WB
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
#else
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
EXPECT_FALSE(_acmA->REDStatus());
#endif
OpenOutFile(_testCntr);
Run();
_outFileB.Close();
RegisterSendCodec('A', kNameISAC, 16000);
#ifdef SUPPORT_RED_WB
// Switch codec, RED should remain.
EXPECT_TRUE(_acmA->REDStatus());
#else
// Switch to a 16 kHz codec, RED should have been switched off.
EXPECT_FALSE(_acmA->REDStatus());
#endif
OpenOutFile(_testCntr);
EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
EXPECT_EQ(0, _acmA->SetREDStatus(false));
EXPECT_FALSE(_acmA->REDStatus());
Run();
_outFileB.Close();
#ifdef SUPPORT_RED_WB
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
#else
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
EXPECT_FALSE(_acmA->REDStatus());
#endif
OpenOutFile(_testCntr);
Run();
_outFileB.Close();
RegisterSendCodec('A', kNameISAC, 32000);
#if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB)
// Switch codec, RED should remain.
EXPECT_TRUE(_acmA->REDStatus());
#else
// Switch to a 32 kHz codec, RED should have been switched off.
EXPECT_FALSE(_acmA->REDStatus());
#endif
OpenOutFile(_testCntr);
EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
EXPECT_EQ(0, _acmA->SetREDStatus(false));
EXPECT_FALSE(_acmA->REDStatus());
#ifdef SUPPORT_RED_SWB
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
#else
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
EXPECT_FALSE(_acmA->REDStatus());
#endif
OpenOutFile(_testCntr);
Run();
_outFileB.Close();
RegisterSendCodec('A', kNameISAC, 32000);
EXPECT_EQ(0, SetVAD(false, false, VADNormal));
#if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB)
OpenOutFile(_testCntr);
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', kNameISAC, 16000);
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', kNameISAC, 32000);
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', kNameISAC, 16000);
EXPECT_TRUE(_acmA->REDStatus());
Run();
_outFileB.Close();
#else
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
EXPECT_FALSE(_acmA->REDStatus());
#endif
#ifndef WEBRTC_CODEC_OPUS
EXPECT_TRUE(false);
printf("Opus needs to be activated to run this test\n");
return;
#endif
RegisterSendCodec('A', kNameOPUS, 48000);
#if defined(SUPPORT_RED_FB) && defined(SUPPORT_RED_SWB) &&\
defined(SUPPORT_RED_WB)
// Switch to codec, RED should remain switched on.
EXPECT_TRUE(_acmA->REDStatus());
#else
EXPECT_FALSE(_acmA->REDStatus());
#endif
// _channelA2B imposes 25% packet loss rate.
EXPECT_EQ(0, _acmA->SetPacketLossRate(25));
#ifdef SUPPORT_RED_FB
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
// Codec FEC and RED are mutually exclusive.
EXPECT_EQ(-1, _acmA->SetCodecFEC(true));
EXPECT_EQ(0, _acmA->SetREDStatus(false));
EXPECT_EQ(0, _acmA->SetCodecFEC(true));
// Codec FEC and RED are mutually exclusive.
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
#else
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
EXPECT_FALSE(_acmA->REDStatus());
EXPECT_EQ(0, _acmA->SetCodecFEC(true));
#endif
EXPECT_TRUE(_acmA->CodecFEC());
OpenOutFile(_testCntr);
Run();
// Switch to L16 with RED.
RegisterSendCodec('A', kNameL16, 8000);
EXPECT_EQ(0, SetVAD(false, false, VADNormal));
// L16 does not support FEC, so FEC should be turned off automatically.
EXPECT_FALSE(_acmA->CodecFEC());
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
Run();
// Switch to Opus again.
RegisterSendCodec('A', kNameOPUS, 48000);
#ifdef SUPPORT_RED_FB
// Switch to codec, RED should remain switched on.
EXPECT_TRUE(_acmA->REDStatus());
#else
EXPECT_FALSE(_acmA->REDStatus());
#endif
EXPECT_EQ(0, _acmA->SetREDStatus(false));
EXPECT_EQ(0, _acmA->SetCodecFEC(false));
Run();
EXPECT_EQ(0, _acmA->SetCodecFEC(true));
_outFileB.Close();
// Codecs does not support internal FEC, cannot enable FEC.
RegisterSendCodec('A', kNameG722, 16000);
EXPECT_FALSE(_acmA->REDStatus());
EXPECT_EQ(-1, _acmA->SetCodecFEC(true));
EXPECT_FALSE(_acmA->CodecFEC());
RegisterSendCodec('A', kNameISAC, 16000);
EXPECT_FALSE(_acmA->REDStatus());
EXPECT_EQ(-1, _acmA->SetCodecFEC(true));
EXPECT_FALSE(_acmA->CodecFEC());
// Codecs does not support internal FEC, disable FEC does not trigger failure.
RegisterSendCodec('A', kNameG722, 16000);
EXPECT_FALSE(_acmA->REDStatus());
EXPECT_EQ(0, _acmA->SetCodecFEC(false));
EXPECT_FALSE(_acmA->CodecFEC());
RegisterSendCodec('A', kNameISAC, 16000);
EXPECT_FALSE(_acmA->REDStatus());
EXPECT_EQ(0, _acmA->SetCodecFEC(false));
EXPECT_FALSE(_acmA->CodecFEC());
#endif // defined(WEBRTC_CODEC_G722)
}
int32_t TestRedFec::SetVAD(bool enableDTX, bool enableVAD, ACMVADMode vadMode) {
return _acmA->SetVAD(enableDTX, enableVAD, vadMode);
}
int16_t TestRedFec::RegisterSendCodec(char side, const char* codecName,
int32_t samplingFreqHz) {
std::cout << std::flush;
AudioCodingModule* myACM;
switch (side) {
case 'A': {
myACM = _acmA.get();
break;
}
case 'B': {
myACM = _acmB.get();
break;
}
default:
return -1;
}
if (myACM == NULL) {
assert(false);
return -1;
}
CodecInst myCodecParam;
EXPECT_GT(AudioCodingModule::Codec(codecName, &myCodecParam,
samplingFreqHz, 1), -1);
EXPECT_GT(myACM->RegisterSendCodec(myCodecParam), -1);
// Initialization was successful.
return 0;
}
void TestRedFec::Run() {
AudioFrame audioFrame;
int32_t outFreqHzB = _outFileB.SamplingFrequency();
while (!_inFileA.EndOfFile()) {
EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0);
EXPECT_GE(_acmA->Add10MsData(audioFrame), 0);
EXPECT_EQ(0, _acmB->PlayoutData10Ms(outFreqHzB, &audioFrame));
_outFileB.Write10MsData(audioFrame.data_, audioFrame.samples_per_channel_);
}
_inFileA.Rewind();
}
void TestRedFec::OpenOutFile(int16_t test_number) {
std::string file_name;
std::stringstream file_stream;
file_stream << webrtc::test::OutputPath();
file_stream << "TestRedFec_outFile_";
file_stream << test_number << ".pcm";
file_name = file_stream.str();
_outFileB.Open(file_name, 16000, "wb");
}
} // namespace webrtc

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_TESTREDFEC_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_TESTREDFEC_H_
#include <string>
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/audio_coding/test/ACMTest.h"
#include "webrtc/modules/audio_coding/test/Channel.h"
#include "webrtc/modules/audio_coding/test/PCMFile.h"
namespace webrtc {
class Config;
class TestRedFec : public ACMTest {
public:
explicit TestRedFec();
~TestRedFec();
void Perform();
private:
// The default value of '-1' indicates that the registration is based only on
// codec name and a sampling frequency matching is not required. This is
// useful for codecs which support several sampling frequency.
int16_t RegisterSendCodec(char side, const char* codecName,
int32_t sampFreqHz = -1);
void Run();
void OpenOutFile(int16_t testNumber);
int32_t SetVAD(bool enableDTX, bool enableVAD, ACMVADMode vadMode);
rtc::scoped_ptr<AudioCodingModule> _acmA;
rtc::scoped_ptr<AudioCodingModule> _acmB;
Channel* _channelA2B;
PCMFile _inFileA;
PCMFile _outFileB;
int16_t _testCntr;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_TESTREDFEC_H_

View File

@ -0,0 +1,838 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_coding/test/TestStereo.h"
#include <assert.h>
#include <string>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/common_types.h"
#include "webrtc/engine_configurations.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h"
#include "webrtc/modules/audio_coding/test/utility.h"
#include "webrtc/system_wrappers/include/trace.h"
#include "webrtc/test/testsupport/fileutils.h"
namespace webrtc {
// Class for simulating packet handling
TestPackStereo::TestPackStereo()
: receiver_acm_(NULL),
seq_no_(0),
timestamp_diff_(0),
last_in_timestamp_(0),
total_bytes_(0),
payload_size_(0),
codec_mode_(kNotSet),
lost_packet_(false) {
}
TestPackStereo::~TestPackStereo() {
}
void TestPackStereo::RegisterReceiverACM(AudioCodingModule* acm) {
receiver_acm_ = acm;
return;
}
int32_t TestPackStereo::SendData(const FrameType frame_type,
const uint8_t payload_type,
const uint32_t timestamp,
const uint8_t* payload_data,
const size_t payload_size,
const RTPFragmentationHeader* fragmentation) {
WebRtcRTPHeader rtp_info;
int32_t status = 0;
rtp_info.header.markerBit = false;
rtp_info.header.ssrc = 0;
rtp_info.header.sequenceNumber = seq_no_++;
rtp_info.header.payloadType = payload_type;
rtp_info.header.timestamp = timestamp;
if (frame_type == kEmptyFrame) {
// Skip this frame
return 0;
}
if (lost_packet_ == false) {
if (frame_type != kAudioFrameCN) {
rtp_info.type.Audio.isCNG = false;
rtp_info.type.Audio.channel = static_cast<int>(codec_mode_);
} else {
rtp_info.type.Audio.isCNG = true;
rtp_info.type.Audio.channel = static_cast<int>(kMono);
}
status = receiver_acm_->IncomingPacket(payload_data, payload_size,
rtp_info);
if (frame_type != kAudioFrameCN) {
payload_size_ = static_cast<int>(payload_size);
} else {
payload_size_ = -1;
}
timestamp_diff_ = timestamp - last_in_timestamp_;
last_in_timestamp_ = timestamp;
total_bytes_ += payload_size;
}
return status;
}
uint16_t TestPackStereo::payload_size() {
return static_cast<uint16_t>(payload_size_);
}
uint32_t TestPackStereo::timestamp_diff() {
return timestamp_diff_;
}
void TestPackStereo::reset_payload_size() {
payload_size_ = 0;
}
void TestPackStereo::set_codec_mode(enum StereoMonoMode mode) {
codec_mode_ = mode;
}
void TestPackStereo::set_lost_packet(bool lost) {
lost_packet_ = lost;
}
TestStereo::TestStereo(int test_mode)
: acm_a_(AudioCodingModule::Create(0)),
acm_b_(AudioCodingModule::Create(1)),
channel_a2b_(NULL),
test_cntr_(0),
pack_size_samp_(0),
pack_size_bytes_(0),
counter_(0)
#ifdef WEBRTC_CODEC_G722
, g722_pltype_(0)
#endif
, l16_8khz_pltype_(-1)
, l16_16khz_pltype_(-1)
, l16_32khz_pltype_(-1)
#ifdef PCMA_AND_PCMU
, pcma_pltype_(-1)
, pcmu_pltype_(-1)
#endif
#ifdef WEBRTC_CODEC_OPUS
, opus_pltype_(-1)
#endif
{
// test_mode = 0 for silent test (auto test)
test_mode_ = test_mode;
}
TestStereo::~TestStereo() {
if (channel_a2b_ != NULL) {
delete channel_a2b_;
channel_a2b_ = NULL;
}
}
void TestStereo::Perform() {
uint16_t frequency_hz;
int audio_channels;
int codec_channels;
bool dtx;
bool vad;
ACMVADMode vad_mode;
// Open both mono and stereo test files in 32 kHz.
const std::string file_name_stereo = webrtc::test::ResourcePath(
"audio_coding/teststereo32kHz", "pcm");
const std::string file_name_mono = webrtc::test::ResourcePath(
"audio_coding/testfile32kHz", "pcm");
frequency_hz = 32000;
in_file_stereo_ = new PCMFile();
in_file_mono_ = new PCMFile();
in_file_stereo_->Open(file_name_stereo, frequency_hz, "rb");
in_file_stereo_->ReadStereo(true);
in_file_mono_->Open(file_name_mono, frequency_hz, "rb");
in_file_mono_->ReadStereo(false);
// Create and initialize two ACMs, one for each side of a one-to-one call.
ASSERT_TRUE((acm_a_.get() != NULL) && (acm_b_.get() != NULL));
EXPECT_EQ(0, acm_a_->InitializeReceiver());
EXPECT_EQ(0, acm_b_->InitializeReceiver());
// Register all available codes as receiving codecs.
uint8_t num_encoders = acm_a_->NumberOfCodecs();
CodecInst my_codec_param;
for (uint8_t n = 0; n < num_encoders; n++) {
EXPECT_EQ(0, acm_b_->Codec(n, &my_codec_param));
EXPECT_EQ(0, acm_b_->RegisterReceiveCodec(my_codec_param));
}
// Test that unregister all receive codecs works.
for (uint8_t n = 0; n < num_encoders; n++) {
EXPECT_EQ(0, acm_b_->Codec(n, &my_codec_param));
EXPECT_EQ(0, acm_b_->UnregisterReceiveCodec(my_codec_param.pltype));
}
// Register all available codes as receiving codecs once more.
for (uint8_t n = 0; n < num_encoders; n++) {
EXPECT_EQ(0, acm_b_->Codec(n, &my_codec_param));
EXPECT_EQ(0, acm_b_->RegisterReceiveCodec(my_codec_param));
}
// Create and connect the channel.
channel_a2b_ = new TestPackStereo;
EXPECT_EQ(0, acm_a_->RegisterTransportCallback(channel_a2b_));
channel_a2b_->RegisterReceiverACM(acm_b_.get());
// Start with setting VAD/DTX, before we know we will send stereo.
// Continue with setting a stereo codec as send codec and verify that
// VAD/DTX gets turned off.
EXPECT_EQ(0, acm_a_->SetVAD(true, true, VADNormal));
EXPECT_EQ(0, acm_a_->VAD(&dtx, &vad, &vad_mode));
EXPECT_TRUE(dtx);
EXPECT_TRUE(vad);
char codec_pcma_temp[] = "PCMA";
RegisterSendCodec('A', codec_pcma_temp, 8000, 64000, 80, 2, pcma_pltype_);
EXPECT_EQ(0, acm_a_->VAD(&dtx, &vad, &vad_mode));
EXPECT_FALSE(dtx);
EXPECT_FALSE(vad);
if (test_mode_ != 0) {
printf("\n");
}
//
// Test Stereo-To-Stereo for all codecs.
//
audio_channels = 2;
codec_channels = 2;
// All codecs are tested for all allowed sampling frequencies, rates and
// packet sizes.
#ifdef WEBRTC_CODEC_G722
if (test_mode_ != 0) {
printf("===========================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Stereo-to-stereo\n");
}
channel_a2b_->set_codec_mode(kStereo);
test_cntr_++;
OpenOutFile(test_cntr_);
char codec_g722[] = "G722";
RegisterSendCodec('A', codec_g722, 16000, 64000, 160, codec_channels,
g722_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_g722, 16000, 64000, 320, codec_channels,
g722_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_g722, 16000, 64000, 480, codec_channels,
g722_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_g722, 16000, 64000, 640, codec_channels,
g722_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_g722, 16000, 64000, 800, codec_channels,
g722_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_g722, 16000, 64000, 960, codec_channels,
g722_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
#endif
if (test_mode_ != 0) {
printf("===========================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Stereo-to-stereo\n");
}
channel_a2b_->set_codec_mode(kStereo);
test_cntr_++;
OpenOutFile(test_cntr_);
char codec_l16[] = "L16";
RegisterSendCodec('A', codec_l16, 8000, 128000, 80, codec_channels,
l16_8khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_l16, 8000, 128000, 160, codec_channels,
l16_8khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_l16, 8000, 128000, 240, codec_channels,
l16_8khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_l16, 8000, 128000, 320, codec_channels,
l16_8khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
if (test_mode_ != 0) {
printf("===========================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Stereo-to-stereo\n");
}
test_cntr_++;
OpenOutFile(test_cntr_);
RegisterSendCodec('A', codec_l16, 16000, 256000, 160, codec_channels,
l16_16khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_l16, 16000, 256000, 320, codec_channels,
l16_16khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_l16, 16000, 256000, 480, codec_channels,
l16_16khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_l16, 16000, 256000, 640, codec_channels,
l16_16khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
if (test_mode_ != 0) {
printf("===========================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Stereo-to-stereo\n");
}
test_cntr_++;
OpenOutFile(test_cntr_);
RegisterSendCodec('A', codec_l16, 32000, 512000, 320, codec_channels,
l16_32khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_l16, 32000, 512000, 640, codec_channels,
l16_32khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
#ifdef PCMA_AND_PCMU
if (test_mode_ != 0) {
printf("===========================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Stereo-to-stereo\n");
}
channel_a2b_->set_codec_mode(kStereo);
audio_channels = 2;
codec_channels = 2;
test_cntr_++;
OpenOutFile(test_cntr_);
char codec_pcma[] = "PCMA";
RegisterSendCodec('A', codec_pcma, 8000, 64000, 80, codec_channels,
pcma_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_pcma, 8000, 64000, 160, codec_channels,
pcma_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_pcma, 8000, 64000, 240, codec_channels,
pcma_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_pcma, 8000, 64000, 320, codec_channels,
pcma_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_pcma, 8000, 64000, 400, codec_channels,
pcma_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_pcma, 8000, 64000, 480, codec_channels,
pcma_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
// Test that VAD/DTX cannot be turned on while sending stereo.
EXPECT_EQ(-1, acm_a_->SetVAD(true, true, VADNormal));
EXPECT_EQ(0, acm_a_->VAD(&dtx, &vad, &vad_mode));
EXPECT_FALSE(dtx);
EXPECT_FALSE(vad);
EXPECT_EQ(0, acm_a_->SetVAD(false, false, VADNormal));
EXPECT_EQ(0, acm_a_->VAD(&dtx, &vad, &vad_mode));
EXPECT_FALSE(dtx);
EXPECT_FALSE(vad);
out_file_.Close();
if (test_mode_ != 0) {
printf("===========================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Stereo-to-stereo\n");
}
test_cntr_++;
OpenOutFile(test_cntr_);
char codec_pcmu[] = "PCMU";
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 80, codec_channels,
pcmu_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 160, codec_channels,
pcmu_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 240, codec_channels,
pcmu_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 320, codec_channels,
pcmu_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 400, codec_channels,
pcmu_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 480, codec_channels,
pcmu_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
#endif
#ifdef WEBRTC_CODEC_OPUS
if (test_mode_ != 0) {
printf("===========================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Stereo-to-stereo\n");
}
channel_a2b_->set_codec_mode(kStereo);
audio_channels = 2;
codec_channels = 2;
test_cntr_++;
OpenOutFile(test_cntr_);
char codec_opus[] = "opus";
// Run Opus with 10 ms frame size.
RegisterSendCodec('A', codec_opus, 48000, 64000, 480, codec_channels,
opus_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
// Run Opus with 20 ms frame size.
RegisterSendCodec('A', codec_opus, 48000, 64000, 480*2, codec_channels,
opus_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
// Run Opus with 40 ms frame size.
RegisterSendCodec('A', codec_opus, 48000, 64000, 480*4, codec_channels,
opus_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
// Run Opus with 60 ms frame size.
RegisterSendCodec('A', codec_opus, 48000, 64000, 480*6, codec_channels,
opus_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
// Run Opus with 20 ms frame size and different bitrates.
RegisterSendCodec('A', codec_opus, 48000, 40000, 960, codec_channels,
opus_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_opus, 48000, 510000, 960, codec_channels,
opus_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
#endif
//
// Test Mono-To-Stereo for all codecs.
//
audio_channels = 1;
codec_channels = 2;
#ifdef WEBRTC_CODEC_G722
if (test_mode_ != 0) {
printf("===============================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Mono-to-stereo\n");
}
test_cntr_++;
channel_a2b_->set_codec_mode(kStereo);
OpenOutFile(test_cntr_);
RegisterSendCodec('A', codec_g722, 16000, 64000, 160, codec_channels,
g722_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
#endif
if (test_mode_ != 0) {
printf("===============================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Mono-to-stereo\n");
}
test_cntr_++;
channel_a2b_->set_codec_mode(kStereo);
OpenOutFile(test_cntr_);
RegisterSendCodec('A', codec_l16, 8000, 128000, 80, codec_channels,
l16_8khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
if (test_mode_ != 0) {
printf("===============================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Mono-to-stereo\n");
}
test_cntr_++;
OpenOutFile(test_cntr_);
RegisterSendCodec('A', codec_l16, 16000, 256000, 160, codec_channels,
l16_16khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
if (test_mode_ != 0) {
printf("===============================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Mono-to-stereo\n");
}
test_cntr_++;
OpenOutFile(test_cntr_);
RegisterSendCodec('A', codec_l16, 32000, 512000, 320, codec_channels,
l16_32khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
#ifdef PCMA_AND_PCMU
if (test_mode_ != 0) {
printf("===============================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Mono-to-stereo\n");
}
test_cntr_++;
channel_a2b_->set_codec_mode(kStereo);
OpenOutFile(test_cntr_);
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 80, codec_channels,
pcmu_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_pcma, 8000, 64000, 80, codec_channels,
pcma_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
#endif
#ifdef WEBRTC_CODEC_OPUS
if (test_mode_ != 0) {
printf("===============================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Mono-to-stereo\n");
}
// Keep encode and decode in stereo.
test_cntr_++;
channel_a2b_->set_codec_mode(kStereo);
OpenOutFile(test_cntr_);
RegisterSendCodec('A', codec_opus, 48000, 64000, 960, codec_channels,
opus_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
// Encode in mono, decode in stereo mode.
RegisterSendCodec('A', codec_opus, 48000, 64000, 960, 1, opus_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
#endif
//
// Test Stereo-To-Mono for all codecs.
//
audio_channels = 2;
codec_channels = 1;
channel_a2b_->set_codec_mode(kMono);
#ifdef WEBRTC_CODEC_G722
// Run stereo audio and mono codec.
if (test_mode_ != 0) {
printf("===============================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Stereo-to-mono\n");
}
test_cntr_++;
OpenOutFile(test_cntr_);
RegisterSendCodec('A', codec_g722, 16000, 64000, 160, codec_channels,
g722_pltype_);
// Make sure it is possible to set VAD/CNG, now that we are sending mono
// again.
EXPECT_EQ(0, acm_a_->SetVAD(true, true, VADNormal));
EXPECT_EQ(0, acm_a_->VAD(&dtx, &vad, &vad_mode));
EXPECT_TRUE(dtx);
EXPECT_TRUE(vad);
EXPECT_EQ(0, acm_a_->SetVAD(false, false, VADNormal));
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
#endif
if (test_mode_ != 0) {
printf("===============================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Stereo-to-mono\n");
}
test_cntr_++;
OpenOutFile(test_cntr_);
RegisterSendCodec('A', codec_l16, 8000, 128000, 80, codec_channels,
l16_8khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
if (test_mode_ != 0) {
printf("===============================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Stereo-to-mono\n");
}
test_cntr_++;
OpenOutFile(test_cntr_);
RegisterSendCodec('A', codec_l16, 16000, 256000, 160, codec_channels,
l16_16khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
if (test_mode_ != 0) {
printf("==============================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Stereo-to-mono\n");
}
test_cntr_++;
OpenOutFile(test_cntr_);
RegisterSendCodec('A', codec_l16, 32000, 512000, 320, codec_channels,
l16_32khz_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
#ifdef PCMA_AND_PCMU
if (test_mode_ != 0) {
printf("===============================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Stereo-to-mono\n");
}
test_cntr_++;
OpenOutFile(test_cntr_);
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 80, codec_channels,
pcmu_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
RegisterSendCodec('A', codec_pcma, 8000, 64000, 80, codec_channels,
pcma_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
#endif
#ifdef WEBRTC_CODEC_OPUS
if (test_mode_ != 0) {
printf("===============================================================\n");
printf("Test number: %d\n", test_cntr_ + 1);
printf("Test type: Stereo-to-mono\n");
}
test_cntr_++;
OpenOutFile(test_cntr_);
// Encode and decode in mono.
RegisterSendCodec('A', codec_opus, 48000, 32000, 960, codec_channels,
opus_pltype_);
CodecInst opus_codec_param;
for (uint8_t n = 0; n < num_encoders; n++) {
EXPECT_EQ(0, acm_b_->Codec(n, &opus_codec_param));
if (!strcmp(opus_codec_param.plname, "opus")) {
opus_codec_param.channels = 1;
EXPECT_EQ(0, acm_b_->RegisterReceiveCodec(opus_codec_param));
break;
}
}
Run(channel_a2b_, audio_channels, codec_channels);
// Encode in stereo, decode in mono.
RegisterSendCodec('A', codec_opus, 48000, 32000, 960, 2, opus_pltype_);
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
// Test switching between decoding mono and stereo for Opus.
// Decode in mono.
test_cntr_++;
OpenOutFile(test_cntr_);
if (test_mode_ != 0) {
// Print out codec and settings
printf("Test number: %d\nCodec: Opus Freq: 48000 Rate :32000 PackSize: 960"
" Decode: mono\n", test_cntr_);
}
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
// Decode in stereo.
test_cntr_++;
OpenOutFile(test_cntr_);
if (test_mode_ != 0) {
// Print out codec and settings
printf("Test number: %d\nCodec: Opus Freq: 48000 Rate :32000 PackSize: 960"
" Decode: stereo\n", test_cntr_);
}
opus_codec_param.channels = 2;
EXPECT_EQ(0, acm_b_->RegisterReceiveCodec(opus_codec_param));
Run(channel_a2b_, audio_channels, 2);
out_file_.Close();
// Decode in mono.
test_cntr_++;
OpenOutFile(test_cntr_);
if (test_mode_ != 0) {
// Print out codec and settings
printf("Test number: %d\nCodec: Opus Freq: 48000 Rate :32000 PackSize: 960"
" Decode: mono\n", test_cntr_);
}
opus_codec_param.channels = 1;
EXPECT_EQ(0, acm_b_->RegisterReceiveCodec(opus_codec_param));
Run(channel_a2b_, audio_channels, codec_channels);
out_file_.Close();
#endif
// Print out which codecs were tested, and which were not, in the run.
if (test_mode_ != 0) {
printf("\nThe following codecs was INCLUDED in the test:\n");
#ifdef WEBRTC_CODEC_G722
printf(" G.722\n");
#endif
printf(" PCM16\n");
printf(" G.711\n");
#ifdef WEBRTC_CODEC_OPUS
printf(" Opus\n");
#endif
printf("\nTo complete the test, listen to the %d number of output "
"files.\n",
test_cntr_);
}
// Delete the file pointers.
delete in_file_stereo_;
delete in_file_mono_;
}
// Register Codec to use in the test
//
// Input: side - which ACM to use, 'A' or 'B'
// codec_name - name to use when register the codec
// sampling_freq_hz - sampling frequency in Herz
// rate - bitrate in bytes
// pack_size - packet size in samples
// channels - number of channels; 1 for mono, 2 for stereo
// payload_type - payload type for the codec
void TestStereo::RegisterSendCodec(char side, char* codec_name,
int32_t sampling_freq_hz, int rate,
int pack_size, int channels,
int payload_type) {
if (test_mode_ != 0) {
// Print out codec and settings
printf("Codec: %s Freq: %d Rate: %d PackSize: %d\n", codec_name,
sampling_freq_hz, rate, pack_size);
}
// Store packet size in samples, used to validate the received packet
pack_size_samp_ = pack_size;
// Store the expected packet size in bytes, used to validate the received
// packet. Add 0.875 to always round up to a whole byte.
pack_size_bytes_ = (uint16_t)(static_cast<float>(pack_size * rate) /
static_cast<float>(sampling_freq_hz * 8) +
0.875);
// Set pointer to the ACM where to register the codec
AudioCodingModule* my_acm = NULL;
switch (side) {
case 'A': {
my_acm = acm_a_.get();
break;
}
case 'B': {
my_acm = acm_b_.get();
break;
}
default:
break;
}
ASSERT_TRUE(my_acm != NULL);
CodecInst my_codec_param;
// Get all codec parameters before registering
EXPECT_GT(AudioCodingModule::Codec(codec_name, &my_codec_param,
sampling_freq_hz, channels), -1);
my_codec_param.rate = rate;
my_codec_param.pacsize = pack_size;
EXPECT_EQ(0, my_acm->RegisterSendCodec(my_codec_param));
send_codec_name_ = codec_name;
}
void TestStereo::Run(TestPackStereo* channel, int in_channels, int out_channels,
int percent_loss) {
AudioFrame audio_frame;
int32_t out_freq_hz_b = out_file_.SamplingFrequency();
uint16_t rec_size;
uint32_t time_stamp_diff;
channel->reset_payload_size();
int error_count = 0;
int variable_bytes = 0;
int variable_packets = 0;
while (1) {
// Simulate packet loss by setting |packet_loss_| to "true" in
// |percent_loss| percent of the loops.
if (percent_loss > 0) {
if (counter_ == floor((100 / percent_loss) + 0.5)) {
counter_ = 0;
channel->set_lost_packet(true);
} else {
channel->set_lost_packet(false);
}
counter_++;
}
// Add 10 msec to ACM
if (in_channels == 1) {
if (in_file_mono_->EndOfFile()) {
break;
}
in_file_mono_->Read10MsData(audio_frame);
} else {
if (in_file_stereo_->EndOfFile()) {
break;
}
in_file_stereo_->Read10MsData(audio_frame);
}
EXPECT_GE(acm_a_->Add10MsData(audio_frame), 0);
// Verify that the received packet size matches the settings.
rec_size = channel->payload_size();
if ((0 < rec_size) & (rec_size < 65535)) {
if (strcmp(send_codec_name_, "opus") == 0) {
// Opus is a variable rate codec, hence calculate the average packet
// size, and later make sure the average is in the right range.
variable_bytes += rec_size;
variable_packets++;
} else {
// For fixed rate codecs, check that packet size is correct.
if ((rec_size != pack_size_bytes_ * out_channels)
&& (pack_size_bytes_ < 65535)) {
error_count++;
}
}
// Verify that the timestamp is updated with expected length
time_stamp_diff = channel->timestamp_diff();
if ((counter_ > 10) && (time_stamp_diff != pack_size_samp_)) {
error_count++;
}
}
// Run received side of ACM
EXPECT_EQ(0, acm_b_->PlayoutData10Ms(out_freq_hz_b, &audio_frame));
// Write output speech to file
out_file_.Write10MsData(
audio_frame.data_,
audio_frame.samples_per_channel_ * audio_frame.num_channels_);
}
EXPECT_EQ(0, error_count);
// Check that packet size is in the right range for variable rate codecs,
// such as Opus.
if (variable_packets > 0) {
variable_bytes /= variable_packets;
EXPECT_NEAR(variable_bytes, pack_size_bytes_, 3);
}
if (in_file_mono_->EndOfFile()) {
in_file_mono_->Rewind();
}
if (in_file_stereo_->EndOfFile()) {
in_file_stereo_->Rewind();
}
// Reset in case we ended with a lost packet
channel->set_lost_packet(false);
}
void TestStereo::OpenOutFile(int16_t test_number) {
std::string file_name;
std::stringstream file_stream;
file_stream << webrtc::test::OutputPath() << "teststereo_out_" << test_number
<< ".pcm";
file_name = file_stream.str();
out_file_.Open(file_name, 32000, "wb");
}
void TestStereo::DisplaySendReceiveCodec() {
auto send_codec = acm_a_->SendCodec();
if (test_mode_ != 0) {
ASSERT_TRUE(send_codec);
printf("%s -> ", send_codec->plname);
}
CodecInst receive_codec;
acm_b_->ReceiveCodec(&receive_codec);
if (test_mode_ != 0) {
printf("%s\n", receive_codec.plname);
}
}
} // namespace webrtc

View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_TESTSTEREO_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_TESTSTEREO_H_
#include <math.h>
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/audio_coding/test/ACMTest.h"
#include "webrtc/modules/audio_coding/test/Channel.h"
#include "webrtc/modules/audio_coding/test/PCMFile.h"
#define PCMA_AND_PCMU
namespace webrtc {
enum StereoMonoMode {
kNotSet,
kMono,
kStereo
};
class TestPackStereo : public AudioPacketizationCallback {
public:
TestPackStereo();
~TestPackStereo();
void RegisterReceiverACM(AudioCodingModule* acm);
int32_t SendData(const FrameType frame_type,
const uint8_t payload_type,
const uint32_t timestamp,
const uint8_t* payload_data,
const size_t payload_size,
const RTPFragmentationHeader* fragmentation) override;
uint16_t payload_size();
uint32_t timestamp_diff();
void reset_payload_size();
void set_codec_mode(StereoMonoMode mode);
void set_lost_packet(bool lost);
private:
AudioCodingModule* receiver_acm_;
int16_t seq_no_;
uint32_t timestamp_diff_;
uint32_t last_in_timestamp_;
uint64_t total_bytes_;
int payload_size_;
StereoMonoMode codec_mode_;
// Simulate packet losses
bool lost_packet_;
};
class TestStereo : public ACMTest {
public:
explicit TestStereo(int test_mode);
~TestStereo();
void Perform() override;
private:
// The default value of '-1' indicates that the registration is based only on
// codec name and a sampling frequncy matching is not required. This is useful
// for codecs which support several sampling frequency.
void RegisterSendCodec(char side, char* codec_name, int32_t samp_freq_hz,
int rate, int pack_size, int channels,
int payload_type);
void Run(TestPackStereo* channel, int in_channels, int out_channels,
int percent_loss = 0);
void OpenOutFile(int16_t test_number);
void DisplaySendReceiveCodec();
int test_mode_;
rtc::scoped_ptr<AudioCodingModule> acm_a_;
rtc::scoped_ptr<AudioCodingModule> acm_b_;
TestPackStereo* channel_a2b_;
PCMFile* in_file_stereo_;
PCMFile* in_file_mono_;
PCMFile out_file_;
int16_t test_cntr_;
uint16_t pack_size_samp_;
uint16_t pack_size_bytes_;
int counter_;
char* send_codec_name_;
// Payload types for stereo codecs and CNG
#ifdef WEBRTC_CODEC_G722
int g722_pltype_;
#endif
int l16_8khz_pltype_;
int l16_16khz_pltype_;
int l16_32khz_pltype_;
#ifdef PCMA_AND_PCMU
int pcma_pltype_;
int pcmu_pltype_;
#endif
#ifdef WEBRTC_CODEC_OPUS
int opus_pltype_;
#endif
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_TESTSTEREO_H_

View File

@ -0,0 +1,271 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_coding/test/TestVADDTX.h"
#include <string>
#include "webrtc/engine_configurations.h"
#include "webrtc/modules/audio_coding/test/PCMFile.h"
#include "webrtc/modules/audio_coding/test/utility.h"
#include "webrtc/test/testsupport/fileutils.h"
namespace webrtc {
#ifdef WEBRTC_CODEC_ISAC
const CodecInst kIsacWb = {103, "ISAC", 16000, 480, 1, 32000};
const CodecInst kIsacSwb = {104, "ISAC", 32000, 960, 1, 56000};
#endif
#ifdef WEBRTC_CODEC_ILBC
const CodecInst kIlbc = {102, "ILBC", 8000, 240, 1, 13300};
#endif
#ifdef WEBRTC_CODEC_OPUS
const CodecInst kOpus = {120, "opus", 48000, 960, 1, 64000};
const CodecInst kOpusStereo = {120, "opus", 48000, 960, 2, 64000};
#endif
ActivityMonitor::ActivityMonitor() {
ResetStatistics();
}
int32_t ActivityMonitor::InFrameType(FrameType frame_type) {
counter_[frame_type]++;
return 0;
}
void ActivityMonitor::PrintStatistics() {
printf("\n");
printf("kEmptyFrame %u\n", counter_[kEmptyFrame]);
printf("kAudioFrameSpeech %u\n", counter_[kAudioFrameSpeech]);
printf("kAudioFrameCN %u\n", counter_[kAudioFrameCN]);
printf("kVideoFrameKey %u\n", counter_[kVideoFrameKey]);
printf("kVideoFrameDelta %u\n", counter_[kVideoFrameDelta]);
printf("\n\n");
}
void ActivityMonitor::ResetStatistics() {
memset(counter_, 0, sizeof(counter_));
}
void ActivityMonitor::GetStatistics(uint32_t* counter) {
memcpy(counter, counter_, sizeof(counter_));
}
TestVadDtx::TestVadDtx()
: acm_send_(AudioCodingModule::Create(0)),
acm_receive_(AudioCodingModule::Create(1)),
channel_(new Channel),
monitor_(new ActivityMonitor) {
EXPECT_EQ(0, acm_send_->RegisterTransportCallback(channel_.get()));
channel_->RegisterReceiverACM(acm_receive_.get());
EXPECT_EQ(0, acm_send_->RegisterVADCallback(monitor_.get()));
}
void TestVadDtx::RegisterCodec(CodecInst codec_param) {
// Set the codec for sending and receiving.
EXPECT_EQ(0, acm_send_->RegisterSendCodec(codec_param));
EXPECT_EQ(0, acm_receive_->RegisterReceiveCodec(codec_param));
channel_->SetIsStereo(codec_param.channels > 1);
}
// Encoding a file and see if the numbers that various packets occur follow
// the expectation.
void TestVadDtx::Run(std::string in_filename, int frequency, int channels,
std::string out_filename, bool append,
const int* expects) {
monitor_->ResetStatistics();
PCMFile in_file;
in_file.Open(in_filename, frequency, "rb");
in_file.ReadStereo(channels > 1);
PCMFile out_file;
if (append) {
out_file.Open(out_filename, kOutputFreqHz, "ab");
} else {
out_file.Open(out_filename, kOutputFreqHz, "wb");
}
uint16_t frame_size_samples = in_file.PayloadLength10Ms();
uint32_t time_stamp = 0x12345678;
AudioFrame audio_frame;
while (!in_file.EndOfFile()) {
in_file.Read10MsData(audio_frame);
audio_frame.timestamp_ = time_stamp;
time_stamp += frame_size_samples;
EXPECT_GE(acm_send_->Add10MsData(audio_frame), 0);
acm_receive_->PlayoutData10Ms(kOutputFreqHz, &audio_frame);
out_file.Write10MsData(audio_frame);
}
in_file.Close();
out_file.Close();
#ifdef PRINT_STAT
monitor_->PrintStatistics();
#endif
uint32_t stats[5];
monitor_->GetStatistics(stats);
monitor_->ResetStatistics();
for (const auto& st : stats) {
int i = &st - stats; // Calculate the current position in stats.
switch (expects[i]) {
case 0: {
EXPECT_EQ(0u, st) << "stats[" << i << "] error.";
break;
}
case 1: {
EXPECT_GT(st, 0u) << "stats[" << i << "] error.";
break;
}
}
}
}
// Following is the implementation of TestWebRtcVadDtx.
TestWebRtcVadDtx::TestWebRtcVadDtx()
: vad_enabled_(false),
dtx_enabled_(false),
output_file_num_(0) {
}
void TestWebRtcVadDtx::Perform() {
// Go through various test cases.
#ifdef WEBRTC_CODEC_ISAC
// Register iSAC WB as send codec
RegisterCodec(kIsacWb);
RunTestCases();
// Register iSAC SWB as send codec
RegisterCodec(kIsacSwb);
RunTestCases();
#endif
#ifdef WEBRTC_CODEC_ILBC
// Register iLBC as send codec
RegisterCodec(kIlbc);
RunTestCases();
#endif
#ifdef WEBRTC_CODEC_OPUS
// Register Opus as send codec
RegisterCodec(kOpus);
RunTestCases();
#endif
}
// Test various configurations on VAD/DTX.
void TestWebRtcVadDtx::RunTestCases() {
// #1 DTX = OFF, VAD = OFF, VADNormal
SetVAD(false, false, VADNormal);
Test(true);
// #2 DTX = ON, VAD = ON, VADAggr
SetVAD(true, true, VADAggr);
Test(false);
// #3 DTX = ON, VAD = ON, VADLowBitrate
SetVAD(true, true, VADLowBitrate);
Test(false);
// #4 DTX = ON, VAD = ON, VADVeryAggr
SetVAD(true, true, VADVeryAggr);
Test(false);
// #5 DTX = ON, VAD = ON, VADNormal
SetVAD(true, true, VADNormal);
Test(false);
}
// Set the expectation and run the test.
void TestWebRtcVadDtx::Test(bool new_outfile) {
int expects[] = {-1, 1, dtx_enabled_, 0, 0};
if (new_outfile) {
output_file_num_++;
}
std::stringstream out_filename;
out_filename << webrtc::test::OutputPath()
<< "testWebRtcVadDtx_outFile_"
<< output_file_num_
<< ".pcm";
Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"),
32000, 1, out_filename.str(), !new_outfile, expects);
}
void TestWebRtcVadDtx::SetVAD(bool enable_dtx, bool enable_vad,
ACMVADMode vad_mode) {
ACMVADMode mode;
EXPECT_EQ(0, acm_send_->SetVAD(enable_dtx, enable_vad, vad_mode));
EXPECT_EQ(0, acm_send_->VAD(&dtx_enabled_, &vad_enabled_, &mode));
auto codec_param = acm_send_->SendCodec();
ASSERT_TRUE(codec_param);
if (STR_CASE_CMP(codec_param->plname, "opus") == 0) {
// If send codec is Opus, WebRTC VAD/DTX cannot be used.
enable_dtx = enable_vad = false;
}
EXPECT_EQ(dtx_enabled_ , enable_dtx); // DTX should be set as expected.
if (dtx_enabled_) {
EXPECT_TRUE(vad_enabled_); // WebRTC DTX cannot run without WebRTC VAD.
} else {
// Using no DTX should not affect setting of VAD.
EXPECT_EQ(enable_vad, vad_enabled_);
}
}
// Following is the implementation of TestOpusDtx.
void TestOpusDtx::Perform() {
#ifdef WEBRTC_CODEC_ISAC
// If we set other codec than Opus, DTX cannot be toggled.
RegisterCodec(kIsacWb);
EXPECT_EQ(-1, acm_send_->EnableOpusDtx());
EXPECT_EQ(-1, acm_send_->DisableOpusDtx());
#endif
#ifdef WEBRTC_CODEC_OPUS
int expects[] = {0, 1, 0, 0, 0};
// Register Opus as send codec
std::string out_filename = webrtc::test::OutputPath() +
"testOpusDtx_outFile_mono.pcm";
RegisterCodec(kOpus);
EXPECT_EQ(0, acm_send_->DisableOpusDtx());
Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"),
32000, 1, out_filename, false, expects);
EXPECT_EQ(0, acm_send_->EnableOpusDtx());
expects[kEmptyFrame] = 1;
Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"),
32000, 1, out_filename, true, expects);
// Register stereo Opus as send codec
out_filename = webrtc::test::OutputPath() + "testOpusDtx_outFile_stereo.pcm";
RegisterCodec(kOpusStereo);
EXPECT_EQ(0, acm_send_->DisableOpusDtx());
expects[kEmptyFrame] = 0;
Run(webrtc::test::ResourcePath("audio_coding/teststereo32kHz", "pcm"),
32000, 2, out_filename, false, expects);
EXPECT_EQ(0, acm_send_->EnableOpusDtx());
expects[kEmptyFrame] = 1;
Run(webrtc::test::ResourcePath("audio_coding/teststereo32kHz", "pcm"),
32000, 2, out_filename, true, expects);
#endif
}
} // namespace webrtc

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_TESTVADDTX_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_TESTVADDTX_H_
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h"
#include "webrtc/modules/audio_coding/test/ACMTest.h"
#include "webrtc/modules/audio_coding/test/Channel.h"
namespace webrtc {
class ActivityMonitor : public ACMVADCallback {
public:
ActivityMonitor();
int32_t InFrameType(FrameType frame_type);
void PrintStatistics();
void ResetStatistics();
void GetStatistics(uint32_t* stats);
private:
// 0 - kEmptyFrame
// 1 - kAudioFrameSpeech
// 2 - kAudioFrameCN
// 3 - kVideoFrameKey (not used by audio)
// 4 - kVideoFrameDelta (not used by audio)
uint32_t counter_[5];
};
// TestVadDtx is to verify that VAD/DTX perform as they should. It runs through
// an audio file and check if the occurrence of various packet types follows
// expectation. TestVadDtx needs its derived class to implement the Perform()
// to put the test together.
class TestVadDtx : public ACMTest {
public:
static const int kOutputFreqHz = 16000;
TestVadDtx();
virtual void Perform() = 0;
protected:
void RegisterCodec(CodecInst codec_param);
// Encoding a file and see if the numbers that various packets occur follow
// the expectation. Saves result to a file.
// expects[x] means
// -1 : do not care,
// 0 : there have been no packets of type |x|,
// 1 : there have been packets of type |x|,
// with |x| indicates the following packet types
// 0 - kEmptyFrame
// 1 - kAudioFrameSpeech
// 2 - kAudioFrameCN
// 3 - kVideoFrameKey (not used by audio)
// 4 - kVideoFrameDelta (not used by audio)
void Run(std::string in_filename, int frequency, int channels,
std::string out_filename, bool append, const int* expects);
rtc::scoped_ptr<AudioCodingModule> acm_send_;
rtc::scoped_ptr<AudioCodingModule> acm_receive_;
rtc::scoped_ptr<Channel> channel_;
rtc::scoped_ptr<ActivityMonitor> monitor_;
};
// TestWebRtcVadDtx is to verify that the WebRTC VAD/DTX perform as they should.
class TestWebRtcVadDtx final : public TestVadDtx {
public:
TestWebRtcVadDtx();
void Perform() override;
private:
void RunTestCases();
void Test(bool new_outfile);
void SetVAD(bool enable_dtx, bool enable_vad, ACMVADMode vad_mode);
bool vad_enabled_;
bool dtx_enabled_;
int output_file_num_;
};
// TestOpusDtx is to verify that the Opus DTX performs as it should.
class TestOpusDtx final : public TestVadDtx {
public:
void Perform() override;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_TESTVADDTX_H_

View File

@ -0,0 +1,171 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <stdio.h>
#include <string>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/audio_coding/test/APITest.h"
#include "webrtc/modules/audio_coding/test/EncodeDecodeTest.h"
#include "webrtc/modules/audio_coding/test/iSACTest.h"
#include "webrtc/modules/audio_coding/test/opus_test.h"
#include "webrtc/modules/audio_coding/test/PacketLossTest.h"
#include "webrtc/modules/audio_coding/test/TestAllCodecs.h"
#include "webrtc/modules/audio_coding/test/TestRedFec.h"
#include "webrtc/modules/audio_coding/test/TestStereo.h"
#include "webrtc/modules/audio_coding/test/TestVADDTX.h"
#include "webrtc/modules/audio_coding/test/TwoWayCommunication.h"
#include "webrtc/system_wrappers/include/trace.h"
#include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/test/testsupport/gtest_disable.h"
using webrtc::Trace;
// This parameter is used to describe how to run the tests. It is normally
// set to 0, and all tests are run in quite mode.
#define ACM_TEST_MODE 0
TEST(AudioCodingModuleTest, TestAllCodecs) {
Trace::CreateTrace();
Trace::SetTraceFile((webrtc::test::OutputPath() +
"acm_allcodecs_trace.txt").c_str());
webrtc::TestAllCodecs(ACM_TEST_MODE).Perform();
Trace::ReturnTrace();
}
TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(TestEncodeDecode)) {
Trace::CreateTrace();
Trace::SetTraceFile((webrtc::test::OutputPath() +
"acm_encodedecode_trace.txt").c_str());
webrtc::EncodeDecodeTest(ACM_TEST_MODE).Perform();
Trace::ReturnTrace();
}
#ifdef WEBRTC_CODEC_RED
#define IF_RED(x) x
#else
#define IF_RED(x) DISABLED_##x
#endif
TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(IF_RED(TestRedFec))) {
Trace::CreateTrace();
Trace::SetTraceFile((webrtc::test::OutputPath() +
"acm_fec_trace.txt").c_str());
webrtc::TestRedFec().Perform();
Trace::ReturnTrace();
}
#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
#define IF_ISAC(x) x
#else
#define IF_ISAC(x) DISABLED_##x
#endif
TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(IF_ISAC(TestIsac))) {
Trace::CreateTrace();
Trace::SetTraceFile((webrtc::test::OutputPath() +
"acm_isac_trace.txt").c_str());
webrtc::ISACTest(ACM_TEST_MODE).Perform();
Trace::ReturnTrace();
}
#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) && \
defined(WEBRTC_CODEC_ILBC) && defined(WEBRTC_CODEC_G722)
#define IF_ALL_CODECS(x) x
#else
#define IF_ALL_CODECS(x) DISABLED_##x
#endif
TEST(AudioCodingModuleTest,
DISABLED_ON_ANDROID(IF_ALL_CODECS(TwoWayCommunication))) {
Trace::CreateTrace();
Trace::SetTraceFile((webrtc::test::OutputPath() +
"acm_twowaycom_trace.txt").c_str());
webrtc::TwoWayCommunication(ACM_TEST_MODE).Perform();
Trace::ReturnTrace();
}
TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(TestStereo)) {
Trace::CreateTrace();
Trace::SetTraceFile((webrtc::test::OutputPath() +
"acm_stereo_trace.txt").c_str());
webrtc::TestStereo(ACM_TEST_MODE).Perform();
Trace::ReturnTrace();
}
TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(TestWebRtcVadDtx)) {
Trace::CreateTrace();
Trace::SetTraceFile((webrtc::test::OutputPath() +
"acm_vaddtx_trace.txt").c_str());
webrtc::TestWebRtcVadDtx().Perform();
Trace::ReturnTrace();
}
TEST(AudioCodingModuleTest, TestOpusDtx) {
Trace::CreateTrace();
Trace::SetTraceFile((webrtc::test::OutputPath() +
"acm_opusdtx_trace.txt").c_str());
webrtc::TestOpusDtx().Perform();
Trace::ReturnTrace();
}
TEST(AudioCodingModuleTest, TestOpus) {
Trace::CreateTrace();
Trace::SetTraceFile((webrtc::test::OutputPath() +
"acm_opus_trace.txt").c_str());
webrtc::OpusTest().Perform();
Trace::ReturnTrace();
}
TEST(AudioCodingModuleTest, TestPacketLoss) {
Trace::CreateTrace();
Trace::SetTraceFile((webrtc::test::OutputPath() +
"acm_packetloss_trace.txt").c_str());
webrtc::PacketLossTest(1, 10, 10, 1).Perform();
Trace::ReturnTrace();
}
TEST(AudioCodingModuleTest, TestPacketLossBurst) {
Trace::CreateTrace();
Trace::SetTraceFile((webrtc::test::OutputPath() +
"acm_packetloss_burst_trace.txt").c_str());
webrtc::PacketLossTest(1, 10, 10, 2).Perform();
Trace::ReturnTrace();
}
TEST(AudioCodingModuleTest, TestPacketLossStereo) {
Trace::CreateTrace();
Trace::SetTraceFile((webrtc::test::OutputPath() +
"acm_packetloss_trace.txt").c_str());
webrtc::PacketLossTest(2, 10, 10, 1).Perform();
Trace::ReturnTrace();
}
TEST(AudioCodingModuleTest, TestPacketLossStereoBurst) {
Trace::CreateTrace();
Trace::SetTraceFile((webrtc::test::OutputPath() +
"acm_packetloss_burst_trace.txt").c_str());
webrtc::PacketLossTest(2, 10, 10, 2).Perform();
Trace::ReturnTrace();
}
// The full API test is too long to run automatically on bots, but can be used
// for offline testing. User interaction is needed.
#ifdef ACM_TEST_FULL_API
TEST(AudioCodingModuleTest, TestAPI) {
Trace::CreateTrace();
Trace::SetTraceFile((webrtc::test::OutputPath() +
"acm_apitest_trace.txt").c_str());
webrtc::APITest().Perform();
Trace::ReturnTrace();
}
#endif

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "TimedTrace.h"
#include <math.h>
double TimedTrace::_timeEllapsedSec = 0;
FILE* TimedTrace::_timedTraceFile = NULL;
TimedTrace::TimedTrace() {
}
TimedTrace::~TimedTrace() {
if (_timedTraceFile != NULL) {
fclose(_timedTraceFile);
}
_timedTraceFile = NULL;
}
int16_t TimedTrace::SetUp(char* fileName) {
if (_timedTraceFile == NULL) {
_timedTraceFile = fopen(fileName, "w");
}
if (_timedTraceFile == NULL) {
return -1;
}
return 0;
}
void TimedTrace::SetTimeEllapsed(double timeEllapsedSec) {
_timeEllapsedSec = timeEllapsedSec;
}
double TimedTrace::TimeEllapsed() {
return _timeEllapsedSec;
}
void TimedTrace::Tick10Msec() {
_timeEllapsedSec += 0.010;
}
void TimedTrace::TimedLogg(char* message) {
unsigned int minutes = (uint32_t) floor(_timeEllapsedSec / 60.0);
double seconds = _timeEllapsedSec - minutes * 60;
//char myFormat[100] = "%8.2f, %3u:%05.2f: %s\n";
if (_timedTraceFile != NULL) {
fprintf(_timedTraceFile, "%8.2f, %3u:%05.2f: %s\n", _timeEllapsedSec,
minutes, seconds, message);
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_TIMEDTRACE_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_TIMEDTRACE_H_
#include "webrtc/typedefs.h"
#include <stdio.h>
#include <stdlib.h>
class TimedTrace {
public:
TimedTrace();
~TimedTrace();
void SetTimeEllapsed(double myTime);
double TimeEllapsed();
void Tick10Msec();
int16_t SetUp(char* fileName);
void TimedLogg(char* message);
private:
static double _timeEllapsedSec;
static FILE* _timedTraceFile;
};
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_TIMEDTRACE_H_

View File

@ -0,0 +1,299 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "TwoWayCommunication.h"
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#ifdef WIN32
#include <Windows.h>
#endif
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/engine_configurations.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/test/PCMFile.h"
#include "webrtc/modules/audio_coding/test/utility.h"
#include "webrtc/system_wrappers/include/trace.h"
#include "webrtc/test/testsupport/fileutils.h"
namespace webrtc {
#define MAX_FILE_NAME_LENGTH_BYTE 500
TwoWayCommunication::TwoWayCommunication(int testMode)
: _acmA(AudioCodingModule::Create(1)),
_acmRefA(AudioCodingModule::Create(3)),
_testMode(testMode) {
AudioCodingModule::Config config;
// The clicks will be more obvious in FAX mode. TODO(henrik.lundin) Really?
config.neteq_config.playout_mode = kPlayoutFax;
config.id = 2;
_acmB.reset(AudioCodingModule::Create(config));
config.id = 4;
_acmRefB.reset(AudioCodingModule::Create(config));
}
TwoWayCommunication::~TwoWayCommunication() {
delete _channel_A2B;
delete _channel_B2A;
delete _channelRef_A2B;
delete _channelRef_B2A;
#ifdef WEBRTC_DTMF_DETECTION
if (_dtmfDetectorA != NULL) {
delete _dtmfDetectorA;
}
if (_dtmfDetectorB != NULL) {
delete _dtmfDetectorB;
}
#endif
_inFileA.Close();
_inFileB.Close();
_outFileA.Close();
_outFileB.Close();
_outFileRefA.Close();
_outFileRefB.Close();
}
void TwoWayCommunication::ChooseCodec(uint8_t* codecID_A,
uint8_t* codecID_B) {
rtc::scoped_ptr<AudioCodingModule> tmpACM(AudioCodingModule::Create(0));
uint8_t noCodec = tmpACM->NumberOfCodecs();
CodecInst codecInst;
printf("List of Supported Codecs\n");
printf("========================\n");
for (uint8_t codecCntr = 0; codecCntr < noCodec; codecCntr++) {
EXPECT_EQ(tmpACM->Codec(codecCntr, &codecInst), 0);
printf("%d- %s\n", codecCntr, codecInst.plname);
}
printf("\nChoose a send codec for side A [0]: ");
char myStr[15] = "";
EXPECT_TRUE(fgets(myStr, 10, stdin) != NULL);
*codecID_A = (uint8_t) atoi(myStr);
printf("\nChoose a send codec for side B [0]: ");
EXPECT_TRUE(fgets(myStr, 10, stdin) != NULL);
*codecID_B = (uint8_t) atoi(myStr);
printf("\n");
}
void TwoWayCommunication::SetUp() {
uint8_t codecID_A;
uint8_t codecID_B;
ChooseCodec(&codecID_A, &codecID_B);
CodecInst codecInst_A;
CodecInst codecInst_B;
CodecInst dummyCodec;
EXPECT_EQ(0, _acmA->Codec(codecID_A, &codecInst_A));
EXPECT_EQ(0, _acmB->Codec(codecID_B, &codecInst_B));
EXPECT_EQ(0, _acmA->Codec(6, &dummyCodec));
//--- Set A codecs
EXPECT_EQ(0, _acmA->RegisterSendCodec(codecInst_A));
EXPECT_EQ(0, _acmA->RegisterReceiveCodec(codecInst_B));
//--- Set ref-A codecs
EXPECT_EQ(0, _acmRefA->RegisterSendCodec(codecInst_A));
EXPECT_EQ(0, _acmRefA->RegisterReceiveCodec(codecInst_B));
//--- Set B codecs
EXPECT_EQ(0, _acmB->RegisterSendCodec(codecInst_B));
EXPECT_EQ(0, _acmB->RegisterReceiveCodec(codecInst_A));
//--- Set ref-B codecs
EXPECT_EQ(0, _acmRefB->RegisterSendCodec(codecInst_B));
EXPECT_EQ(0, _acmRefB->RegisterReceiveCodec(codecInst_A));
uint16_t frequencyHz;
//--- Input A
std::string in_file_name = webrtc::test::ResourcePath(
"audio_coding/testfile32kHz", "pcm");
frequencyHz = 32000;
printf("Enter input file at side A [%s]: ", in_file_name.c_str());
PCMFile::ChooseFile(&in_file_name, 499, &frequencyHz);
_inFileA.Open(in_file_name, frequencyHz, "rb");
//--- Output A
std::string out_file_a = webrtc::test::OutputPath() + "outA.pcm";
printf("Output file at side A: %s\n", out_file_a.c_str());
printf("Sampling frequency (in Hz) of the above file: %u\n", frequencyHz);
_outFileA.Open(out_file_a, frequencyHz, "wb");
std::string ref_file_name = webrtc::test::OutputPath() + "ref_outA.pcm";
_outFileRefA.Open(ref_file_name, frequencyHz, "wb");
//--- Input B
in_file_name = webrtc::test::ResourcePath("audio_coding/testfile32kHz",
"pcm");
frequencyHz = 32000;
printf("\n\nEnter input file at side B [%s]: ", in_file_name.c_str());
PCMFile::ChooseFile(&in_file_name, 499, &frequencyHz);
_inFileB.Open(in_file_name, frequencyHz, "rb");
//--- Output B
std::string out_file_b = webrtc::test::OutputPath() + "outB.pcm";
printf("Output file at side B: %s\n", out_file_b.c_str());
printf("Sampling frequency (in Hz) of the above file: %u\n", frequencyHz);
_outFileB.Open(out_file_b, frequencyHz, "wb");
ref_file_name = webrtc::test::OutputPath() + "ref_outB.pcm";
_outFileRefB.Open(ref_file_name, frequencyHz, "wb");
//--- Set A-to-B channel
_channel_A2B = new Channel;
_acmA->RegisterTransportCallback(_channel_A2B);
_channel_A2B->RegisterReceiverACM(_acmB.get());
//--- Do the same for the reference
_channelRef_A2B = new Channel;
_acmRefA->RegisterTransportCallback(_channelRef_A2B);
_channelRef_A2B->RegisterReceiverACM(_acmRefB.get());
//--- Set B-to-A channel
_channel_B2A = new Channel;
_acmB->RegisterTransportCallback(_channel_B2A);
_channel_B2A->RegisterReceiverACM(_acmA.get());
//--- Do the same for reference
_channelRef_B2A = new Channel;
_acmRefB->RegisterTransportCallback(_channelRef_B2A);
_channelRef_B2A->RegisterReceiverACM(_acmRefA.get());
}
void TwoWayCommunication::SetUpAutotest() {
CodecInst codecInst_A;
CodecInst codecInst_B;
CodecInst dummyCodec;
EXPECT_EQ(0, _acmA->Codec("ISAC", &codecInst_A, 16000, 1));
EXPECT_EQ(0, _acmB->Codec("L16", &codecInst_B, 8000, 1));
EXPECT_EQ(0, _acmA->Codec(6, &dummyCodec));
//--- Set A codecs
EXPECT_EQ(0, _acmA->RegisterSendCodec(codecInst_A));
EXPECT_EQ(0, _acmA->RegisterReceiveCodec(codecInst_B));
//--- Set ref-A codecs
EXPECT_GT(_acmRefA->RegisterSendCodec(codecInst_A), -1);
EXPECT_GT(_acmRefA->RegisterReceiveCodec(codecInst_B), -1);
//--- Set B codecs
EXPECT_GT(_acmB->RegisterSendCodec(codecInst_B), -1);
EXPECT_GT(_acmB->RegisterReceiveCodec(codecInst_A), -1);
//--- Set ref-B codecs
EXPECT_EQ(0, _acmRefB->RegisterSendCodec(codecInst_B));
EXPECT_EQ(0, _acmRefB->RegisterReceiveCodec(codecInst_A));
uint16_t frequencyHz;
//--- Input A and B
std::string in_file_name = webrtc::test::ResourcePath(
"audio_coding/testfile32kHz", "pcm");
frequencyHz = 16000;
_inFileA.Open(in_file_name, frequencyHz, "rb");
_inFileB.Open(in_file_name, frequencyHz, "rb");
//--- Output A
std::string output_file_a = webrtc::test::OutputPath() + "outAutotestA.pcm";
frequencyHz = 16000;
_outFileA.Open(output_file_a, frequencyHz, "wb");
std::string output_ref_file_a = webrtc::test::OutputPath()
+ "ref_outAutotestA.pcm";
_outFileRefA.Open(output_ref_file_a, frequencyHz, "wb");
//--- Output B
std::string output_file_b = webrtc::test::OutputPath() + "outAutotestB.pcm";
frequencyHz = 16000;
_outFileB.Open(output_file_b, frequencyHz, "wb");
std::string output_ref_file_b = webrtc::test::OutputPath()
+ "ref_outAutotestB.pcm";
_outFileRefB.Open(output_ref_file_b, frequencyHz, "wb");
//--- Set A-to-B channel
_channel_A2B = new Channel;
_acmA->RegisterTransportCallback(_channel_A2B);
_channel_A2B->RegisterReceiverACM(_acmB.get());
//--- Do the same for the reference
_channelRef_A2B = new Channel;
_acmRefA->RegisterTransportCallback(_channelRef_A2B);
_channelRef_A2B->RegisterReceiverACM(_acmRefB.get());
//--- Set B-to-A channel
_channel_B2A = new Channel;
_acmB->RegisterTransportCallback(_channel_B2A);
_channel_B2A->RegisterReceiverACM(_acmA.get());
//--- Do the same for reference
_channelRef_B2A = new Channel;
_acmRefB->RegisterTransportCallback(_channelRef_B2A);
_channelRef_B2A->RegisterReceiverACM(_acmRefA.get());
}
void TwoWayCommunication::Perform() {
if (_testMode == 0) {
SetUpAutotest();
} else {
SetUp();
}
unsigned int msecPassed = 0;
unsigned int secPassed = 0;
int32_t outFreqHzA = _outFileA.SamplingFrequency();
int32_t outFreqHzB = _outFileB.SamplingFrequency();
AudioFrame audioFrame;
auto codecInst_B = _acmB->SendCodec();
ASSERT_TRUE(codecInst_B);
// In the following loop we tests that the code can handle misuse of the APIs.
// In the middle of a session with data flowing between two sides, called A
// and B, APIs will be called, and the code should continue to run, and be
// able to recover.
while (!_inFileA.EndOfFile() && !_inFileB.EndOfFile()) {
msecPassed += 10;
EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0);
EXPECT_GE(_acmA->Add10MsData(audioFrame), 0);
EXPECT_GE(_acmRefA->Add10MsData(audioFrame), 0);
EXPECT_GT(_inFileB.Read10MsData(audioFrame), 0);
EXPECT_GE(_acmB->Add10MsData(audioFrame), 0);
EXPECT_GE(_acmRefB->Add10MsData(audioFrame), 0);
EXPECT_EQ(0, _acmA->PlayoutData10Ms(outFreqHzA, &audioFrame));
_outFileA.Write10MsData(audioFrame);
EXPECT_EQ(0, _acmRefA->PlayoutData10Ms(outFreqHzA, &audioFrame));
_outFileRefA.Write10MsData(audioFrame);
EXPECT_EQ(0, _acmB->PlayoutData10Ms(outFreqHzB, &audioFrame));
_outFileB.Write10MsData(audioFrame);
EXPECT_EQ(0, _acmRefB->PlayoutData10Ms(outFreqHzB, &audioFrame));
_outFileRefB.Write10MsData(audioFrame);
// Update time counters each time a second of data has passed.
if (msecPassed >= 1000) {
msecPassed = 0;
secPassed++;
}
// Re-register send codec on side B.
if (((secPassed % 5) == 4) && (msecPassed >= 990)) {
EXPECT_EQ(0, _acmB->RegisterSendCodec(*codecInst_B));
EXPECT_TRUE(_acmB->SendCodec());
}
// Initialize receiver on side A.
if (((secPassed % 7) == 6) && (msecPassed == 0))
EXPECT_EQ(0, _acmA->InitializeReceiver());
// Re-register codec on side A.
if (((secPassed % 7) == 6) && (msecPassed >= 990)) {
EXPECT_EQ(0, _acmA->RegisterReceiveCodec(*codecInst_B));
}
}
}
} // namespace webrtc

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_TWOWAYCOMMUNICATION_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_TWOWAYCOMMUNICATION_H_
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/audio_coding/test/ACMTest.h"
#include "webrtc/modules/audio_coding/test/Channel.h"
#include "webrtc/modules/audio_coding/test/PCMFile.h"
#include "webrtc/modules/audio_coding/test/utility.h"
namespace webrtc {
class TwoWayCommunication : public ACMTest {
public:
explicit TwoWayCommunication(int testMode);
~TwoWayCommunication();
void Perform();
private:
void ChooseCodec(uint8_t* codecID_A, uint8_t* codecID_B);
void SetUp();
void SetUpAutotest();
rtc::scoped_ptr<AudioCodingModule> _acmA;
rtc::scoped_ptr<AudioCodingModule> _acmB;
rtc::scoped_ptr<AudioCodingModule> _acmRefA;
rtc::scoped_ptr<AudioCodingModule> _acmRefB;
Channel* _channel_A2B;
Channel* _channel_B2A;
Channel* _channelRef_A2B;
Channel* _channelRef_B2A;
PCMFile _inFileA;
PCMFile _inFileB;
PCMFile _outFileA;
PCMFile _outFileB;
PCMFile _outFileRefA;
PCMFile _outFileRefB;
int _testMode;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_TWOWAYCOMMUNICATION_H_

View File

@ -0,0 +1,265 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <assert.h>
#include <math.h>
#include <iostream>
#include "gflags/gflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/common.h"
#include "webrtc/common_types.h"
#include "webrtc/engine_configurations.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h"
#include "webrtc/modules/audio_coding/acm2/acm_common_defs.h"
#include "webrtc/modules/audio_coding/test/Channel.h"
#include "webrtc/modules/audio_coding/test/PCMFile.h"
#include "webrtc/modules/audio_coding/test/utility.h"
#include "webrtc/system_wrappers/include/event_wrapper.h"
#include "webrtc/test/testsupport/fileutils.h"
DEFINE_string(codec, "isac", "Codec Name");
DEFINE_int32(sample_rate_hz, 16000, "Sampling rate in Hertz.");
DEFINE_int32(num_channels, 1, "Number of Channels.");
DEFINE_string(input_file, "", "Input file, PCM16 32 kHz, optional.");
DEFINE_int32(delay, 0, "Delay in millisecond.");
DEFINE_bool(dtx, false, "Enable DTX at the sender side.");
DEFINE_bool(packet_loss, false, "Apply packet loss, c.f. Channel{.cc, .h}.");
DEFINE_bool(fec, false, "Use Forward Error Correction (FEC).");
namespace webrtc {
namespace {
struct CodecSettings {
char name[50];
int sample_rate_hz;
int num_channels;
};
struct AcmSettings {
bool dtx;
bool fec;
};
struct TestSettings {
CodecSettings codec;
AcmSettings acm;
bool packet_loss;
};
} // namespace
class DelayTest {
public:
DelayTest()
: acm_a_(AudioCodingModule::Create(0)),
acm_b_(AudioCodingModule::Create(1)),
channel_a2b_(new Channel),
test_cntr_(0),
encoding_sample_rate_hz_(8000) {}
~DelayTest() {
if (channel_a2b_ != NULL) {
delete channel_a2b_;
channel_a2b_ = NULL;
}
in_file_a_.Close();
}
void Initialize() {
test_cntr_ = 0;
std::string file_name = webrtc::test::ResourcePath(
"audio_coding/testfile32kHz", "pcm");
if (FLAGS_input_file.size() > 0)
file_name = FLAGS_input_file;
in_file_a_.Open(file_name, 32000, "rb");
ASSERT_EQ(0, acm_a_->InitializeReceiver()) <<
"Couldn't initialize receiver.\n";
ASSERT_EQ(0, acm_b_->InitializeReceiver()) <<
"Couldn't initialize receiver.\n";
if (FLAGS_delay > 0) {
ASSERT_EQ(0, acm_b_->SetMinimumPlayoutDelay(FLAGS_delay)) <<
"Failed to set minimum delay.\n";
}
int num_encoders = acm_a_->NumberOfCodecs();
CodecInst my_codec_param;
for (int n = 0; n < num_encoders; n++) {
EXPECT_EQ(0, acm_b_->Codec(n, &my_codec_param)) <<
"Failed to get codec.";
if (STR_CASE_CMP(my_codec_param.plname, "opus") == 0)
my_codec_param.channels = 1;
else if (my_codec_param.channels > 1)
continue;
if (STR_CASE_CMP(my_codec_param.plname, "CN") == 0 &&
my_codec_param.plfreq == 48000)
continue;
if (STR_CASE_CMP(my_codec_param.plname, "telephone-event") == 0)
continue;
ASSERT_EQ(0, acm_b_->RegisterReceiveCodec(my_codec_param)) <<
"Couldn't register receive codec.\n";
}
// Create and connect the channel
ASSERT_EQ(0, acm_a_->RegisterTransportCallback(channel_a2b_)) <<
"Couldn't register Transport callback.\n";
channel_a2b_->RegisterReceiverACM(acm_b_.get());
}
void Perform(const TestSettings* config, size_t num_tests, int duration_sec,
const char* output_prefix) {
for (size_t n = 0; n < num_tests; ++n) {
ApplyConfig(config[n]);
Run(duration_sec, output_prefix);
}
}
private:
void ApplyConfig(const TestSettings& config) {
printf("====================================\n");
printf("Test %d \n"
"Codec: %s, %d kHz, %d channel(s)\n"
"ACM: DTX %s, FEC %s\n"
"Channel: %s\n",
++test_cntr_, config.codec.name, config.codec.sample_rate_hz,
config.codec.num_channels, config.acm.dtx ? "on" : "off",
config.acm.fec ? "on" : "off",
config.packet_loss ? "with packet-loss" : "no packet-loss");
SendCodec(config.codec);
ConfigAcm(config.acm);
ConfigChannel(config.packet_loss);
}
void SendCodec(const CodecSettings& config) {
CodecInst my_codec_param;
ASSERT_EQ(0, AudioCodingModule::Codec(
config.name, &my_codec_param, config.sample_rate_hz,
config.num_channels)) << "Specified codec is not supported.\n";
encoding_sample_rate_hz_ = my_codec_param.plfreq;
ASSERT_EQ(0, acm_a_->RegisterSendCodec(my_codec_param)) <<
"Failed to register send-codec.\n";
}
void ConfigAcm(const AcmSettings& config) {
ASSERT_EQ(0, acm_a_->SetVAD(config.dtx, config.dtx, VADAggr)) <<
"Failed to set VAD.\n";
ASSERT_EQ(0, acm_a_->SetREDStatus(config.fec)) <<
"Failed to set RED.\n";
}
void ConfigChannel(bool packet_loss) {
channel_a2b_->SetFECTestWithPacketLoss(packet_loss);
}
void OpenOutFile(const char* output_id) {
std::stringstream file_stream;
file_stream << "delay_test_" << FLAGS_codec << "_" << FLAGS_sample_rate_hz
<< "Hz" << "_" << FLAGS_delay << "ms.pcm";
std::cout << "Output file: " << file_stream.str() << std::endl << std::endl;
std::string file_name = webrtc::test::OutputPath() + file_stream.str();
out_file_b_.Open(file_name.c_str(), 32000, "wb");
}
void Run(int duration_sec, const char* output_prefix) {
OpenOutFile(output_prefix);
AudioFrame audio_frame;
uint32_t out_freq_hz_b = out_file_b_.SamplingFrequency();
int num_frames = 0;
int in_file_frames = 0;
uint32_t playout_ts;
uint32_t received_ts;
double average_delay = 0;
double inst_delay_sec = 0;
while (num_frames < (duration_sec * 100)) {
if (in_file_a_.EndOfFile()) {
in_file_a_.Rewind();
}
// Print delay information every 16 frame
if ((num_frames & 0x3F) == 0x3F) {
NetworkStatistics statistics;
acm_b_->GetNetworkStatistics(&statistics);
fprintf(stdout, "delay: min=%3d max=%3d mean=%3d median=%3d"
" ts-based average = %6.3f, "
"curr buff-lev = %4u opt buff-lev = %4u \n",
statistics.minWaitingTimeMs, statistics.maxWaitingTimeMs,
statistics.meanWaitingTimeMs, statistics.medianWaitingTimeMs,
average_delay, statistics.currentBufferSize,
statistics.preferredBufferSize);
fflush (stdout);
}
in_file_a_.Read10MsData(audio_frame);
ASSERT_GE(acm_a_->Add10MsData(audio_frame), 0);
ASSERT_EQ(0, acm_b_->PlayoutData10Ms(out_freq_hz_b, &audio_frame));
out_file_b_.Write10MsData(
audio_frame.data_,
audio_frame.samples_per_channel_ * audio_frame.num_channels_);
acm_b_->PlayoutTimestamp(&playout_ts);
received_ts = channel_a2b_->LastInTimestamp();
inst_delay_sec = static_cast<uint32_t>(received_ts - playout_ts)
/ static_cast<double>(encoding_sample_rate_hz_);
if (num_frames > 10)
average_delay = 0.95 * average_delay + 0.05 * inst_delay_sec;
++num_frames;
++in_file_frames;
}
out_file_b_.Close();
}
rtc::scoped_ptr<AudioCodingModule> acm_a_;
rtc::scoped_ptr<AudioCodingModule> acm_b_;
Channel* channel_a2b_;
PCMFile in_file_a_;
PCMFile out_file_b_;
int test_cntr_;
int encoding_sample_rate_hz_;
};
} // namespace webrtc
int main(int argc, char* argv[]) {
google::ParseCommandLineFlags(&argc, &argv, true);
webrtc::TestSettings test_setting;
strcpy(test_setting.codec.name, FLAGS_codec.c_str());
if (FLAGS_sample_rate_hz != 8000 &&
FLAGS_sample_rate_hz != 16000 &&
FLAGS_sample_rate_hz != 32000 &&
FLAGS_sample_rate_hz != 48000) {
std::cout << "Invalid sampling rate.\n";
return 1;
}
test_setting.codec.sample_rate_hz = FLAGS_sample_rate_hz;
if (FLAGS_num_channels < 1 || FLAGS_num_channels > 2) {
std::cout << "Only mono and stereo are supported.\n";
return 1;
}
test_setting.codec.num_channels = FLAGS_num_channels;
test_setting.acm.dtx = FLAGS_dtx;
test_setting.acm.fec = FLAGS_fec;
test_setting.packet_loss = FLAGS_packet_loss;
webrtc::DelayTest delay_test;
delay_test.Initialize();
delay_test.Perform(&test_setting, 1, 240, "delay_test");
return 0;
}

View File

@ -0,0 +1,339 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_coding/test/iSACTest.h"
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#if _WIN32
#include <windows.h>
#elif WEBRTC_LINUX
#include <time.h>
#else
#include <sys/time.h>
#include <time.h>
#endif
#include "webrtc/modules/audio_coding/acm2/acm_common_defs.h"
#include "webrtc/modules/audio_coding/test/utility.h"
#include "webrtc/system_wrappers/include/event_wrapper.h"
#include "webrtc/system_wrappers/include/tick_util.h"
#include "webrtc/system_wrappers/include/trace.h"
#include "webrtc/test/testsupport/fileutils.h"
namespace webrtc {
void SetISACConfigDefault(ACMTestISACConfig& isacConfig) {
isacConfig.currentRateBitPerSec = 0;
isacConfig.currentFrameSizeMsec = 0;
isacConfig.encodingMode = -1;
isacConfig.initRateBitPerSec = 0;
isacConfig.initFrameSizeInMsec = 0;
isacConfig.enforceFrameSize = false;
return;
}
int16_t SetISAConfig(ACMTestISACConfig& isacConfig, AudioCodingModule* acm,
int testMode) {
if ((isacConfig.currentRateBitPerSec != 0)
|| (isacConfig.currentFrameSizeMsec != 0)) {
auto sendCodec = acm->SendCodec();
EXPECT_TRUE(sendCodec);
if (isacConfig.currentRateBitPerSec < 0) {
// Register iSAC in adaptive (channel-dependent) mode.
sendCodec->rate = -1;
EXPECT_EQ(0, acm->RegisterSendCodec(*sendCodec));
} else {
if (isacConfig.currentRateBitPerSec != 0) {
sendCodec->rate = isacConfig.currentRateBitPerSec;
}
if (isacConfig.currentFrameSizeMsec != 0) {
sendCodec->pacsize = isacConfig.currentFrameSizeMsec
* (sendCodec->plfreq / 1000);
}
EXPECT_EQ(0, acm->RegisterSendCodec(*sendCodec));
}
}
return 0;
}
ISACTest::ISACTest(int testMode)
: _acmA(AudioCodingModule::Create(1)),
_acmB(AudioCodingModule::Create(2)),
_testMode(testMode) {}
ISACTest::~ISACTest() {}
void ISACTest::Setup() {
int codecCntr;
CodecInst codecParam;
for (codecCntr = 0; codecCntr < AudioCodingModule::NumberOfCodecs();
codecCntr++) {
EXPECT_EQ(0, AudioCodingModule::Codec(codecCntr, &codecParam));
if (!STR_CASE_CMP(codecParam.plname, "ISAC")
&& codecParam.plfreq == 16000) {
memcpy(&_paramISAC16kHz, &codecParam, sizeof(CodecInst));
_idISAC16kHz = codecCntr;
}
if (!STR_CASE_CMP(codecParam.plname, "ISAC")
&& codecParam.plfreq == 32000) {
memcpy(&_paramISAC32kHz, &codecParam, sizeof(CodecInst));
_idISAC32kHz = codecCntr;
}
}
// Register both iSAC-wb & iSAC-swb in both sides as receiver codecs.
EXPECT_EQ(0, _acmA->RegisterReceiveCodec(_paramISAC16kHz));
EXPECT_EQ(0, _acmA->RegisterReceiveCodec(_paramISAC32kHz));
EXPECT_EQ(0, _acmB->RegisterReceiveCodec(_paramISAC16kHz));
EXPECT_EQ(0, _acmB->RegisterReceiveCodec(_paramISAC32kHz));
//--- Set A-to-B channel
_channel_A2B.reset(new Channel);
EXPECT_EQ(0, _acmA->RegisterTransportCallback(_channel_A2B.get()));
_channel_A2B->RegisterReceiverACM(_acmB.get());
//--- Set B-to-A channel
_channel_B2A.reset(new Channel);
EXPECT_EQ(0, _acmB->RegisterTransportCallback(_channel_B2A.get()));
_channel_B2A->RegisterReceiverACM(_acmA.get());
file_name_swb_ = webrtc::test::ResourcePath("audio_coding/testfile32kHz",
"pcm");
EXPECT_EQ(0, _acmB->RegisterSendCodec(_paramISAC16kHz));
EXPECT_EQ(0, _acmA->RegisterSendCodec(_paramISAC32kHz));
_inFileA.Open(file_name_swb_, 32000, "rb");
std::string fileNameA = webrtc::test::OutputPath() + "testisac_a.pcm";
std::string fileNameB = webrtc::test::OutputPath() + "testisac_b.pcm";
_outFileA.Open(fileNameA, 32000, "wb");
_outFileB.Open(fileNameB, 32000, "wb");
while (!_inFileA.EndOfFile()) {
Run10ms();
}
CodecInst receiveCodec;
EXPECT_EQ(0, _acmA->ReceiveCodec(&receiveCodec));
EXPECT_EQ(0, _acmB->ReceiveCodec(&receiveCodec));
_inFileA.Close();
_outFileA.Close();
_outFileB.Close();
}
void ISACTest::Perform() {
Setup();
int16_t testNr = 0;
ACMTestISACConfig wbISACConfig;
ACMTestISACConfig swbISACConfig;
SetISACConfigDefault(wbISACConfig);
SetISACConfigDefault(swbISACConfig);
wbISACConfig.currentRateBitPerSec = -1;
swbISACConfig.currentRateBitPerSec = -1;
testNr++;
EncodeDecode(testNr, wbISACConfig, swbISACConfig);
if (_testMode != 0) {
SetISACConfigDefault(wbISACConfig);
SetISACConfigDefault(swbISACConfig);
wbISACConfig.currentRateBitPerSec = -1;
swbISACConfig.currentRateBitPerSec = -1;
wbISACConfig.initRateBitPerSec = 13000;
wbISACConfig.initFrameSizeInMsec = 60;
swbISACConfig.initRateBitPerSec = 20000;
swbISACConfig.initFrameSizeInMsec = 30;
testNr++;
EncodeDecode(testNr, wbISACConfig, swbISACConfig);
SetISACConfigDefault(wbISACConfig);
SetISACConfigDefault(swbISACConfig);
wbISACConfig.currentRateBitPerSec = 20000;
swbISACConfig.currentRateBitPerSec = 48000;
testNr++;
EncodeDecode(testNr, wbISACConfig, swbISACConfig);
wbISACConfig.currentRateBitPerSec = 16000;
swbISACConfig.currentRateBitPerSec = 30000;
wbISACConfig.currentFrameSizeMsec = 60;
testNr++;
EncodeDecode(testNr, wbISACConfig, swbISACConfig);
}
SetISACConfigDefault(wbISACConfig);
SetISACConfigDefault(swbISACConfig);
testNr++;
EncodeDecode(testNr, wbISACConfig, swbISACConfig);
testNr++;
if (_testMode == 0) {
SwitchingSamplingRate(testNr, 4);
} else {
SwitchingSamplingRate(testNr, 80);
}
}
void ISACTest::Run10ms() {
AudioFrame audioFrame;
EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0);
EXPECT_GE(_acmA->Add10MsData(audioFrame), 0);
EXPECT_GE(_acmB->Add10MsData(audioFrame), 0);
EXPECT_EQ(0, _acmA->PlayoutData10Ms(32000, &audioFrame));
_outFileA.Write10MsData(audioFrame);
EXPECT_EQ(0, _acmB->PlayoutData10Ms(32000, &audioFrame));
_outFileB.Write10MsData(audioFrame);
}
void ISACTest::EncodeDecode(int testNr, ACMTestISACConfig& wbISACConfig,
ACMTestISACConfig& swbISACConfig) {
// Files in Side A and B
_inFileA.Open(file_name_swb_, 32000, "rb", true);
_inFileB.Open(file_name_swb_, 32000, "rb", true);
std::string file_name_out;
std::stringstream file_stream_a;
std::stringstream file_stream_b;
file_stream_a << webrtc::test::OutputPath();
file_stream_b << webrtc::test::OutputPath();
file_stream_a << "out_iSACTest_A_" << testNr << ".pcm";
file_stream_b << "out_iSACTest_B_" << testNr << ".pcm";
file_name_out = file_stream_a.str();
_outFileA.Open(file_name_out, 32000, "wb");
file_name_out = file_stream_b.str();
_outFileB.Open(file_name_out, 32000, "wb");
EXPECT_EQ(0, _acmA->RegisterSendCodec(_paramISAC16kHz));
EXPECT_EQ(0, _acmA->RegisterSendCodec(_paramISAC32kHz));
EXPECT_EQ(0, _acmB->RegisterSendCodec(_paramISAC32kHz));
EXPECT_EQ(0, _acmB->RegisterSendCodec(_paramISAC16kHz));
// Side A is sending super-wideband, and side B is sending wideband.
SetISAConfig(swbISACConfig, _acmA.get(), _testMode);
SetISAConfig(wbISACConfig, _acmB.get(), _testMode);
bool adaptiveMode = false;
if ((swbISACConfig.currentRateBitPerSec == -1)
|| (wbISACConfig.currentRateBitPerSec == -1)) {
adaptiveMode = true;
}
_myTimer.Reset();
_channel_A2B->ResetStats();
_channel_B2A->ResetStats();
char currentTime[500];
EventTimerWrapper* myEvent = EventTimerWrapper::Create();
EXPECT_TRUE(myEvent->StartTimer(true, 10));
while (!(_inFileA.EndOfFile() || _inFileA.Rewinded())) {
Run10ms();
_myTimer.Tick10ms();
_myTimer.CurrentTimeHMS(currentTime);
if ((adaptiveMode) && (_testMode != 0)) {
myEvent->Wait(5000);
EXPECT_TRUE(_acmA->SendCodec());
EXPECT_TRUE(_acmB->SendCodec());
}
}
if (_testMode != 0) {
printf("\n\nSide A statistics\n\n");
_channel_A2B->PrintStats(_paramISAC32kHz);
printf("\n\nSide B statistics\n\n");
_channel_B2A->PrintStats(_paramISAC16kHz);
}
_channel_A2B->ResetStats();
_channel_B2A->ResetStats();
_outFileA.Close();
_outFileB.Close();
_inFileA.Close();
_inFileB.Close();
}
void ISACTest::SwitchingSamplingRate(int testNr, int maxSampRateChange) {
// Files in Side A
_inFileA.Open(file_name_swb_, 32000, "rb");
_inFileB.Open(file_name_swb_, 32000, "rb");
std::string file_name_out;
std::stringstream file_stream_a;
std::stringstream file_stream_b;
file_stream_a << webrtc::test::OutputPath();
file_stream_b << webrtc::test::OutputPath();
file_stream_a << "out_iSACTest_A_" << testNr << ".pcm";
file_stream_b << "out_iSACTest_B_" << testNr << ".pcm";
file_name_out = file_stream_a.str();
_outFileA.Open(file_name_out, 32000, "wb");
file_name_out = file_stream_b.str();
_outFileB.Open(file_name_out, 32000, "wb");
// Start with side A sending super-wideband and side B seding wideband.
// Toggle sending wideband/super-wideband in this test.
EXPECT_EQ(0, _acmA->RegisterSendCodec(_paramISAC32kHz));
EXPECT_EQ(0, _acmB->RegisterSendCodec(_paramISAC16kHz));
int numSendCodecChanged = 0;
_myTimer.Reset();
char currentTime[50];
while (numSendCodecChanged < (maxSampRateChange << 1)) {
Run10ms();
_myTimer.Tick10ms();
_myTimer.CurrentTimeHMS(currentTime);
if (_testMode == 2)
printf("\r%s", currentTime);
if (_inFileA.EndOfFile()) {
if (_inFileA.SamplingFrequency() == 16000) {
// Switch side A to send super-wideband.
_inFileA.Close();
_inFileA.Open(file_name_swb_, 32000, "rb");
EXPECT_EQ(0, _acmA->RegisterSendCodec(_paramISAC32kHz));
} else {
// Switch side A to send wideband.
_inFileA.Close();
_inFileA.Open(file_name_swb_, 32000, "rb");
EXPECT_EQ(0, _acmA->RegisterSendCodec(_paramISAC16kHz));
}
numSendCodecChanged++;
}
if (_inFileB.EndOfFile()) {
if (_inFileB.SamplingFrequency() == 16000) {
// Switch side B to send super-wideband.
_inFileB.Close();
_inFileB.Open(file_name_swb_, 32000, "rb");
EXPECT_EQ(0, _acmB->RegisterSendCodec(_paramISAC32kHz));
} else {
// Switch side B to send wideband.
_inFileB.Close();
_inFileB.Open(file_name_swb_, 32000, "rb");
EXPECT_EQ(0, _acmB->RegisterSendCodec(_paramISAC16kHz));
}
numSendCodecChanged++;
}
}
_outFileA.Close();
_outFileB.Close();
_inFileA.Close();
_inFileB.Close();
}
} // namespace webrtc

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_ISACTEST_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_ISACTEST_H_
#include <string.h>
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/audio_coding/test/ACMTest.h"
#include "webrtc/modules/audio_coding/test/Channel.h"
#include "webrtc/modules/audio_coding/test/PCMFile.h"
#include "webrtc/modules/audio_coding/test/utility.h"
#define MAX_FILE_NAME_LENGTH_BYTE 500
#define NO_OF_CLIENTS 15
namespace webrtc {
struct ACMTestISACConfig {
int32_t currentRateBitPerSec;
int16_t currentFrameSizeMsec;
int16_t encodingMode;
uint32_t initRateBitPerSec;
int16_t initFrameSizeInMsec;
bool enforceFrameSize;
};
class ISACTest : public ACMTest {
public:
explicit ISACTest(int testMode);
~ISACTest();
void Perform();
private:
void Setup();
void Run10ms();
void EncodeDecode(int testNr, ACMTestISACConfig& wbISACConfig,
ACMTestISACConfig& swbISACConfig);
void SwitchingSamplingRate(int testNr, int maxSampRateChange);
rtc::scoped_ptr<AudioCodingModule> _acmA;
rtc::scoped_ptr<AudioCodingModule> _acmB;
rtc::scoped_ptr<Channel> _channel_A2B;
rtc::scoped_ptr<Channel> _channel_B2A;
PCMFile _inFileA;
PCMFile _inFileB;
PCMFile _outFileA;
PCMFile _outFileB;
uint8_t _idISAC16kHz;
uint8_t _idISAC32kHz;
CodecInst _paramISAC16kHz;
CodecInst _paramISAC32kHz;
std::string file_name_swb_;
ACMTestTimer _myTimer;
int _testMode;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_ISACTEST_H_

View File

@ -0,0 +1,307 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <stdio.h>
#include "gflags/gflags.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/audio_coding/test/Channel.h"
#include "webrtc/modules/audio_coding/test/PCMFile.h"
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc/test/testsupport/fileutils.h"
// Codec.
DEFINE_string(codec, "opus", "Codec Name");
DEFINE_int32(codec_sample_rate_hz, 48000, "Sampling rate in Hertz.");
DEFINE_int32(codec_channels, 1, "Number of channels of the codec.");
// PCM input/output.
DEFINE_string(input, "", "Input PCM file at 16 kHz.");
DEFINE_bool(input_stereo, false, "Input is stereo.");
DEFINE_int32(input_fs_hz, 32000, "Input sample rate Hz.");
DEFINE_string(output, "insert_rtp_with_timing_out.pcm", "OutputFile");
DEFINE_int32(output_fs_hz, 32000, "Output sample rate Hz");
// Timing files
DEFINE_string(seq_num, "seq_num", "Sequence number file.");
DEFINE_string(send_ts, "send_timestamp", "Send timestamp file.");
DEFINE_string(receive_ts, "last_rec_timestamp", "Receive timestamp file");
// Delay logging
DEFINE_string(delay, "", "Log for delay.");
// Other setups
DEFINE_bool(verbose, false, "Verbosity.");
DEFINE_double(loss_rate, 0, "Rate of packet loss < 1");
const int32_t kAudioPlayedOut = 0x00000001;
const int32_t kPacketPushedIn = 0x00000001 << 1;
const int kPlayoutPeriodMs = 10;
namespace webrtc {
class InsertPacketWithTiming {
public:
InsertPacketWithTiming()
: sender_clock_(new SimulatedClock(0)),
receiver_clock_(new SimulatedClock(0)),
send_acm_(AudioCodingModule::Create(0, sender_clock_)),
receive_acm_(AudioCodingModule::Create(0, receiver_clock_)),
channel_(new Channel),
seq_num_fid_(fopen(FLAGS_seq_num.c_str(), "rt")),
send_ts_fid_(fopen(FLAGS_send_ts.c_str(), "rt")),
receive_ts_fid_(fopen(FLAGS_receive_ts.c_str(), "rt")),
pcm_out_fid_(fopen(FLAGS_output.c_str(), "wb")),
samples_in_1ms_(48),
num_10ms_in_codec_frame_(2), // Typical 20 ms frames.
time_to_insert_packet_ms_(3), // An arbitrary offset on pushing packet.
next_receive_ts_(0),
time_to_playout_audio_ms_(kPlayoutPeriodMs),
loss_threshold_(0),
playout_timing_fid_(fopen("playout_timing.txt", "wt")) {}
void SetUp() {
ASSERT_TRUE(sender_clock_ != NULL);
ASSERT_TRUE(receiver_clock_ != NULL);
ASSERT_TRUE(send_acm_.get() != NULL);
ASSERT_TRUE(receive_acm_.get() != NULL);
ASSERT_TRUE(channel_ != NULL);
ASSERT_TRUE(seq_num_fid_ != NULL);
ASSERT_TRUE(send_ts_fid_ != NULL);
ASSERT_TRUE(receive_ts_fid_ != NULL);
ASSERT_TRUE(playout_timing_fid_ != NULL);
next_receive_ts_ = ReceiveTimestamp();
CodecInst codec;
ASSERT_EQ(0, AudioCodingModule::Codec(FLAGS_codec.c_str(), &codec,
FLAGS_codec_sample_rate_hz,
FLAGS_codec_channels));
ASSERT_EQ(0, receive_acm_->InitializeReceiver());
ASSERT_EQ(0, send_acm_->RegisterSendCodec(codec));
ASSERT_EQ(0, receive_acm_->RegisterReceiveCodec(codec));
// Set codec-dependent parameters.
samples_in_1ms_ = codec.plfreq / 1000;
num_10ms_in_codec_frame_ = codec.pacsize / (codec.plfreq / 100);
channel_->RegisterReceiverACM(receive_acm_.get());
send_acm_->RegisterTransportCallback(channel_);
if (FLAGS_input.size() == 0) {
std::string file_name = test::ResourcePath("audio_coding/testfile32kHz",
"pcm");
pcm_in_fid_.Open(file_name, 32000, "r", true); // auto-rewind
std::cout << "Input file " << file_name << " 32 kHz mono." << std::endl;
} else {
pcm_in_fid_.Open(FLAGS_input, static_cast<uint16_t>(FLAGS_input_fs_hz),
"r", true); // auto-rewind
std::cout << "Input file " << FLAGS_input << "at " << FLAGS_input_fs_hz
<< " Hz in " << ((FLAGS_input_stereo) ? "stereo." : "mono.")
<< std::endl;
pcm_in_fid_.ReadStereo(FLAGS_input_stereo);
}
ASSERT_TRUE(pcm_out_fid_ != NULL);
std::cout << "Output file " << FLAGS_output << " at " << FLAGS_output_fs_hz
<< " Hz." << std::endl;
// Other setups
if (FLAGS_loss_rate > 0)
loss_threshold_ = RAND_MAX * FLAGS_loss_rate;
else
loss_threshold_ = 0;
}
void TickOneMillisecond(uint32_t* action) {
// One millisecond passed.
time_to_insert_packet_ms_--;
time_to_playout_audio_ms_--;
sender_clock_->AdvanceTimeMilliseconds(1);
receiver_clock_->AdvanceTimeMilliseconds(1);
// Reset action.
*action = 0;
// Is it time to pull audio?
if (time_to_playout_audio_ms_ == 0) {
time_to_playout_audio_ms_ = kPlayoutPeriodMs;
receive_acm_->PlayoutData10Ms(static_cast<int>(FLAGS_output_fs_hz),
&frame_);
fwrite(frame_.data_, sizeof(frame_.data_[0]),
frame_.samples_per_channel_ * frame_.num_channels_, pcm_out_fid_);
*action |= kAudioPlayedOut;
}
// Is it time to push in next packet?
if (time_to_insert_packet_ms_ <= .5) {
*action |= kPacketPushedIn;
// Update time-to-insert packet.
uint32_t t = next_receive_ts_;
next_receive_ts_ = ReceiveTimestamp();
time_to_insert_packet_ms_ += static_cast<float>(next_receive_ts_ - t) /
samples_in_1ms_;
// Push in just enough audio.
for (int n = 0; n < num_10ms_in_codec_frame_; n++) {
pcm_in_fid_.Read10MsData(frame_);
EXPECT_GE(send_acm_->Add10MsData(frame_), 0);
}
// Set the parameters for the packet to be pushed in receiver ACM right
// now.
uint32_t ts = SendTimestamp();
int seq_num = SequenceNumber();
bool lost = false;
channel_->set_send_timestamp(ts);
channel_->set_sequence_number(seq_num);
if (loss_threshold_ > 0 && rand() < loss_threshold_) {
channel_->set_num_packets_to_drop(1);
lost = true;
}
if (FLAGS_verbose) {
if (!lost) {
std::cout << "\nInserting packet number " << seq_num
<< " timestamp " << ts << std::endl;
} else {
std::cout << "\nLost packet number " << seq_num
<< " timestamp " << ts << std::endl;
}
}
}
}
void TearDown() {
delete channel_;
fclose(seq_num_fid_);
fclose(send_ts_fid_);
fclose(receive_ts_fid_);
fclose(pcm_out_fid_);
pcm_in_fid_.Close();
}
~InsertPacketWithTiming() {
delete sender_clock_;
delete receiver_clock_;
}
// Are there more info to simulate.
bool HasPackets() {
if (feof(seq_num_fid_) || feof(send_ts_fid_) || feof(receive_ts_fid_))
return false;
return true;
}
// Jitter buffer delay.
void Delay(int* optimal_delay, int* current_delay) {
NetworkStatistics statistics;
receive_acm_->GetNetworkStatistics(&statistics);
*optimal_delay = statistics.preferredBufferSize;
*current_delay = statistics.currentBufferSize;
}
private:
uint32_t SendTimestamp() {
uint32_t t;
EXPECT_EQ(1, fscanf(send_ts_fid_, "%u\n", &t));
return t;
}
uint32_t ReceiveTimestamp() {
uint32_t t;
EXPECT_EQ(1, fscanf(receive_ts_fid_, "%u\n", &t));
return t;
}
int SequenceNumber() {
int n;
EXPECT_EQ(1, fscanf(seq_num_fid_, "%d\n", &n));
return n;
}
// This class just creates these pointers, not deleting them. They are deleted
// by the associated ACM.
SimulatedClock* sender_clock_;
SimulatedClock* receiver_clock_;
rtc::scoped_ptr<AudioCodingModule> send_acm_;
rtc::scoped_ptr<AudioCodingModule> receive_acm_;
Channel* channel_;
FILE* seq_num_fid_; // Input (text), one sequence number per line.
FILE* send_ts_fid_; // Input (text), one send timestamp per line.
FILE* receive_ts_fid_; // Input (text), one receive timestamp per line.
FILE* pcm_out_fid_; // Output PCM16.
PCMFile pcm_in_fid_; // Input PCM16.
int samples_in_1ms_;
// TODO(turajs): this can be computed from the send timestamp, but there is
// some complication to account for lost and reordered packets.
int num_10ms_in_codec_frame_;
float time_to_insert_packet_ms_;
uint32_t next_receive_ts_;
uint32_t time_to_playout_audio_ms_;
AudioFrame frame_;
double loss_threshold_;
// Output (text), sequence number, playout timestamp, time (ms) of playout,
// per line.
FILE* playout_timing_fid_;
};
} // webrtc
int main(int argc, char* argv[]) {
google::ParseCommandLineFlags(&argc, &argv, true);
webrtc::InsertPacketWithTiming test;
test.SetUp();
FILE* delay_log = NULL;
if (FLAGS_delay.size() > 0) {
delay_log = fopen(FLAGS_delay.c_str(), "wt");
if (delay_log == NULL) {
std::cout << "Cannot open the file to log delay values." << std::endl;
exit(1);
}
}
uint32_t action_taken;
int optimal_delay_ms;
int current_delay_ms;
while (test.HasPackets()) {
test.TickOneMillisecond(&action_taken);
if (action_taken != 0) {
test.Delay(&optimal_delay_ms, &current_delay_ms);
if (delay_log != NULL) {
fprintf(delay_log, "%3d %3d\n", optimal_delay_ms, current_delay_ms);
}
}
}
std::cout << std::endl;
test.TearDown();
if (delay_log != NULL)
fclose(delay_log);
}

View File

@ -0,0 +1,380 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_coding/test/opus_test.h"
#include <assert.h>
#include <string>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/common_types.h"
#include "webrtc/engine_configurations.h"
#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h"
#include "webrtc/modules/audio_coding/test/TestStereo.h"
#include "webrtc/modules/audio_coding/test/utility.h"
#include "webrtc/system_wrappers/include/trace.h"
#include "webrtc/test/testsupport/fileutils.h"
namespace webrtc {
OpusTest::OpusTest()
: acm_receiver_(AudioCodingModule::Create(0)),
channel_a2b_(NULL),
counter_(0),
payload_type_(255),
rtp_timestamp_(0) {}
OpusTest::~OpusTest() {
if (channel_a2b_ != NULL) {
delete channel_a2b_;
channel_a2b_ = NULL;
}
if (opus_mono_encoder_ != NULL) {
WebRtcOpus_EncoderFree(opus_mono_encoder_);
opus_mono_encoder_ = NULL;
}
if (opus_stereo_encoder_ != NULL) {
WebRtcOpus_EncoderFree(opus_stereo_encoder_);
opus_stereo_encoder_ = NULL;
}
if (opus_mono_decoder_ != NULL) {
WebRtcOpus_DecoderFree(opus_mono_decoder_);
opus_mono_decoder_ = NULL;
}
if (opus_stereo_decoder_ != NULL) {
WebRtcOpus_DecoderFree(opus_stereo_decoder_);
opus_stereo_decoder_ = NULL;
}
}
void OpusTest::Perform() {
#ifndef WEBRTC_CODEC_OPUS
// Opus isn't defined, exit.
return;
#else
uint16_t frequency_hz;
int audio_channels;
int16_t test_cntr = 0;
// Open both mono and stereo test files in 32 kHz.
const std::string file_name_stereo =
webrtc::test::ResourcePath("audio_coding/teststereo32kHz", "pcm");
const std::string file_name_mono =
webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
frequency_hz = 32000;
in_file_stereo_.Open(file_name_stereo, frequency_hz, "rb");
in_file_stereo_.ReadStereo(true);
in_file_mono_.Open(file_name_mono, frequency_hz, "rb");
in_file_mono_.ReadStereo(false);
// Create Opus encoders for mono and stereo.
ASSERT_GT(WebRtcOpus_EncoderCreate(&opus_mono_encoder_, 1, 0), -1);
ASSERT_GT(WebRtcOpus_EncoderCreate(&opus_stereo_encoder_, 2, 1), -1);
// Create Opus decoders for mono and stereo for stand-alone testing of Opus.
ASSERT_GT(WebRtcOpus_DecoderCreate(&opus_mono_decoder_, 1), -1);
ASSERT_GT(WebRtcOpus_DecoderCreate(&opus_stereo_decoder_, 2), -1);
WebRtcOpus_DecoderInit(opus_mono_decoder_);
WebRtcOpus_DecoderInit(opus_stereo_decoder_);
ASSERT_TRUE(acm_receiver_.get() != NULL);
EXPECT_EQ(0, acm_receiver_->InitializeReceiver());
// Register Opus stereo as receiving codec.
CodecInst opus_codec_param;
int codec_id = acm_receiver_->Codec("opus", 48000, 2);
EXPECT_EQ(0, acm_receiver_->Codec(codec_id, &opus_codec_param));
payload_type_ = opus_codec_param.pltype;
EXPECT_EQ(0, acm_receiver_->RegisterReceiveCodec(opus_codec_param));
// Create and connect the channel.
channel_a2b_ = new TestPackStereo;
channel_a2b_->RegisterReceiverACM(acm_receiver_.get());
//
// Test Stereo.
//
channel_a2b_->set_codec_mode(kStereo);
audio_channels = 2;
test_cntr++;
OpenOutFile(test_cntr);
// Run Opus with 2.5 ms frame size.
Run(channel_a2b_, audio_channels, 64000, 120);
// Run Opus with 5 ms frame size.
Run(channel_a2b_, audio_channels, 64000, 240);
// Run Opus with 10 ms frame size.
Run(channel_a2b_, audio_channels, 64000, 480);
// Run Opus with 20 ms frame size.
Run(channel_a2b_, audio_channels, 64000, 960);
// Run Opus with 40 ms frame size.
Run(channel_a2b_, audio_channels, 64000, 1920);
// Run Opus with 60 ms frame size.
Run(channel_a2b_, audio_channels, 64000, 2880);
out_file_.Close();
out_file_standalone_.Close();
//
// Test Opus stereo with packet-losses.
//
test_cntr++;
OpenOutFile(test_cntr);
// Run Opus with 20 ms frame size, 1% packet loss.
Run(channel_a2b_, audio_channels, 64000, 960, 1);
// Run Opus with 20 ms frame size, 5% packet loss.
Run(channel_a2b_, audio_channels, 64000, 960, 5);
// Run Opus with 20 ms frame size, 10% packet loss.
Run(channel_a2b_, audio_channels, 64000, 960, 10);
out_file_.Close();
out_file_standalone_.Close();
//
// Test Mono.
//
channel_a2b_->set_codec_mode(kMono);
audio_channels = 1;
test_cntr++;
OpenOutFile(test_cntr);
// Register Opus mono as receiving codec.
opus_codec_param.channels = 1;
EXPECT_EQ(0, acm_receiver_->RegisterReceiveCodec(opus_codec_param));
// Run Opus with 2.5 ms frame size.
Run(channel_a2b_, audio_channels, 32000, 120);
// Run Opus with 5 ms frame size.
Run(channel_a2b_, audio_channels, 32000, 240);
// Run Opus with 10 ms frame size.
Run(channel_a2b_, audio_channels, 32000, 480);
// Run Opus with 20 ms frame size.
Run(channel_a2b_, audio_channels, 32000, 960);
// Run Opus with 40 ms frame size.
Run(channel_a2b_, audio_channels, 32000, 1920);
// Run Opus with 60 ms frame size.
Run(channel_a2b_, audio_channels, 32000, 2880);
out_file_.Close();
out_file_standalone_.Close();
//
// Test Opus mono with packet-losses.
//
test_cntr++;
OpenOutFile(test_cntr);
// Run Opus with 20 ms frame size, 1% packet loss.
Run(channel_a2b_, audio_channels, 64000, 960, 1);
// Run Opus with 20 ms frame size, 5% packet loss.
Run(channel_a2b_, audio_channels, 64000, 960, 5);
// Run Opus with 20 ms frame size, 10% packet loss.
Run(channel_a2b_, audio_channels, 64000, 960, 10);
// Close the files.
in_file_stereo_.Close();
in_file_mono_.Close();
out_file_.Close();
out_file_standalone_.Close();
#endif
}
void OpusTest::Run(TestPackStereo* channel, int channels, int bitrate,
int frame_length, int percent_loss) {
AudioFrame audio_frame;
int32_t out_freq_hz_b = out_file_.SamplingFrequency();
const int kBufferSizeSamples = 480 * 12 * 2; // Can hold 120 ms stereo audio.
int16_t audio[kBufferSizeSamples];
int16_t out_audio[kBufferSizeSamples];
int16_t audio_type;
int written_samples = 0;
int read_samples = 0;
int decoded_samples = 0;
bool first_packet = true;
uint32_t start_time_stamp = 0;
channel->reset_payload_size();
counter_ = 0;
// Set encoder rate.
EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_mono_encoder_, bitrate));
EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_stereo_encoder_, bitrate));
#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_ARCH_ARM)
// If we are on Android, iOS and/or ARM, use a lower complexity setting as
// default.
const int kOpusComplexity5 = 5;
EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_mono_encoder_, kOpusComplexity5));
EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_stereo_encoder_,
kOpusComplexity5));
#endif
// Make sure the runtime is less than 60 seconds to pass Android test.
for (size_t audio_length = 0; audio_length < 10000; audio_length += 10) {
bool lost_packet = false;
// Get 10 msec of audio.
if (channels == 1) {
if (in_file_mono_.EndOfFile()) {
break;
}
in_file_mono_.Read10MsData(audio_frame);
} else {
if (in_file_stereo_.EndOfFile()) {
break;
}
in_file_stereo_.Read10MsData(audio_frame);
}
// If input audio is sampled at 32 kHz, resampling to 48 kHz is required.
EXPECT_EQ(480,
resampler_.Resample10Msec(audio_frame.data_,
audio_frame.sample_rate_hz_,
48000,
channels,
kBufferSizeSamples - written_samples,
&audio[written_samples]));
written_samples += 480 * channels;
// Sometimes we need to loop over the audio vector to produce the right
// number of packets.
int loop_encode = (written_samples - read_samples) /
(channels * frame_length);
if (loop_encode > 0) {
const int kMaxBytes = 1000; // Maximum number of bytes for one packet.
size_t bitstream_len_byte;
uint8_t bitstream[kMaxBytes];
for (int i = 0; i < loop_encode; i++) {
int bitstream_len_byte_int = WebRtcOpus_Encode(
(channels == 1) ? opus_mono_encoder_ : opus_stereo_encoder_,
&audio[read_samples], frame_length, kMaxBytes, bitstream);
ASSERT_GE(bitstream_len_byte_int, 0);
bitstream_len_byte = static_cast<size_t>(bitstream_len_byte_int);
// Simulate packet loss by setting |packet_loss_| to "true" in
// |percent_loss| percent of the loops.
// TODO(tlegrand): Move handling of loss simulation to TestPackStereo.
if (percent_loss > 0) {
if (counter_ == floor((100 / percent_loss) + 0.5)) {
counter_ = 0;
lost_packet = true;
channel->set_lost_packet(true);
} else {
lost_packet = false;
channel->set_lost_packet(false);
}
counter_++;
}
// Run stand-alone Opus decoder, or decode PLC.
if (channels == 1) {
if (!lost_packet) {
decoded_samples += WebRtcOpus_Decode(
opus_mono_decoder_, bitstream, bitstream_len_byte,
&out_audio[decoded_samples * channels], &audio_type);
} else {
decoded_samples += WebRtcOpus_DecodePlc(
opus_mono_decoder_, &out_audio[decoded_samples * channels], 1);
}
} else {
if (!lost_packet) {
decoded_samples += WebRtcOpus_Decode(
opus_stereo_decoder_, bitstream, bitstream_len_byte,
&out_audio[decoded_samples * channels], &audio_type);
} else {
decoded_samples += WebRtcOpus_DecodePlc(
opus_stereo_decoder_, &out_audio[decoded_samples * channels],
1);
}
}
// Send data to the channel. "channel" will handle the loss simulation.
channel->SendData(kAudioFrameSpeech, payload_type_, rtp_timestamp_,
bitstream, bitstream_len_byte, NULL);
if (first_packet) {
first_packet = false;
start_time_stamp = rtp_timestamp_;
}
rtp_timestamp_ += frame_length;
read_samples += frame_length * channels;
}
if (read_samples == written_samples) {
read_samples = 0;
written_samples = 0;
}
}
// Run received side of ACM.
ASSERT_EQ(0, acm_receiver_->PlayoutData10Ms(out_freq_hz_b, &audio_frame));
// Write output speech to file.
out_file_.Write10MsData(
audio_frame.data_,
audio_frame.samples_per_channel_ * audio_frame.num_channels_);
// Write stand-alone speech to file.
out_file_standalone_.Write10MsData(
out_audio, static_cast<size_t>(decoded_samples) * channels);
if (audio_frame.timestamp_ > start_time_stamp) {
// Number of channels should be the same for both stand-alone and
// ACM-decoding.
EXPECT_EQ(audio_frame.num_channels_, channels);
}
decoded_samples = 0;
}
if (in_file_mono_.EndOfFile()) {
in_file_mono_.Rewind();
}
if (in_file_stereo_.EndOfFile()) {
in_file_stereo_.Rewind();
}
// Reset in case we ended with a lost packet.
channel->set_lost_packet(false);
}
void OpusTest::OpenOutFile(int test_number) {
std::string file_name;
std::stringstream file_stream;
file_stream << webrtc::test::OutputPath() << "opustest_out_"
<< test_number << ".pcm";
file_name = file_stream.str();
out_file_.Open(file_name, 48000, "wb");
file_stream.str("");
file_name = file_stream.str();
file_stream << webrtc::test::OutputPath() << "opusstandalone_out_"
<< test_number << ".pcm";
file_name = file_stream.str();
out_file_standalone_.Open(file_name, 48000, "wb");
}
} // namespace webrtc

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_OPUS_TEST_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_OPUS_TEST_H_
#include <math.h>
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
#include "webrtc/modules/audio_coding/acm2/acm_resampler.h"
#include "webrtc/modules/audio_coding/test/ACMTest.h"
#include "webrtc/modules/audio_coding/test/Channel.h"
#include "webrtc/modules/audio_coding/test/PCMFile.h"
#include "webrtc/modules/audio_coding/test/TestStereo.h"
namespace webrtc {
class OpusTest : public ACMTest {
public:
OpusTest();
~OpusTest();
void Perform();
private:
void Run(TestPackStereo* channel, int channels, int bitrate, int frame_length,
int percent_loss = 0);
void OpenOutFile(int test_number);
rtc::scoped_ptr<AudioCodingModule> acm_receiver_;
TestPackStereo* channel_a2b_;
PCMFile in_file_stereo_;
PCMFile in_file_mono_;
PCMFile out_file_;
PCMFile out_file_standalone_;
int counter_;
uint8_t payload_type_;
int rtp_timestamp_;
acm2::ACMResampler resampler_;
WebRtcOpusEncInst* opus_mono_encoder_;
WebRtcOpusEncInst* opus_stereo_encoder_;
WebRtcOpusDecInst* opus_mono_decoder_;
WebRtcOpusDecInst* opus_stereo_decoder_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_OPUS_TEST_H_

View File

@ -0,0 +1,223 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/codecs/pcm16b/pcm16b.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/audio_coding/test/utility.h"
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/system_wrappers/include/sleep.h"
#include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/test/testsupport/gtest_disable.h"
namespace webrtc {
class TargetDelayTest : public ::testing::Test {
protected:
TargetDelayTest() : acm_(AudioCodingModule::Create(0)) {}
~TargetDelayTest() {}
void SetUp() {
EXPECT_TRUE(acm_.get() != NULL);
CodecInst codec;
ASSERT_EQ(0, AudioCodingModule::Codec("L16", &codec, kSampleRateHz, 1));
ASSERT_EQ(0, acm_->InitializeReceiver());
ASSERT_EQ(0, acm_->RegisterReceiveCodec(codec));
rtp_info_.header.payloadType = codec.pltype;
rtp_info_.header.timestamp = 0;
rtp_info_.header.ssrc = 0x12345678;
rtp_info_.header.markerBit = false;
rtp_info_.header.sequenceNumber = 0;
rtp_info_.type.Audio.channel = 1;
rtp_info_.type.Audio.isCNG = false;
rtp_info_.frameType = kAudioFrameSpeech;
int16_t audio[kFrameSizeSamples];
const int kRange = 0x7FF; // 2047, easy for masking.
for (size_t n = 0; n < kFrameSizeSamples; ++n)
audio[n] = (rand() & kRange) - kRange / 2;
WebRtcPcm16b_Encode(audio, kFrameSizeSamples, payload_);
}
void OutOfRangeInput() {
EXPECT_EQ(-1, SetMinimumDelay(-1));
EXPECT_EQ(-1, SetMinimumDelay(10001));
}
void NoTargetDelayBufferSizeChanges() {
for (int n = 0; n < 30; ++n) // Run enough iterations.
Run(true);
int clean_optimal_delay = GetCurrentOptimalDelayMs();
Run(false); // Run with jitter.
int jittery_optimal_delay = GetCurrentOptimalDelayMs();
EXPECT_GT(jittery_optimal_delay, clean_optimal_delay);
int required_delay = RequiredDelay();
EXPECT_GT(required_delay, 0);
EXPECT_NEAR(required_delay, jittery_optimal_delay, 1);
}
void WithTargetDelayBufferNotChanging() {
// A target delay that is one packet larger than jitter.
const int kTargetDelayMs = (kInterarrivalJitterPacket + 1) *
kNum10msPerFrame * 10;
ASSERT_EQ(0, SetMinimumDelay(kTargetDelayMs));
for (int n = 0; n < 30; ++n) // Run enough iterations to fill the buffer.
Run(true);
int clean_optimal_delay = GetCurrentOptimalDelayMs();
EXPECT_EQ(kTargetDelayMs, clean_optimal_delay);
Run(false); // Run with jitter.
int jittery_optimal_delay = GetCurrentOptimalDelayMs();
EXPECT_EQ(jittery_optimal_delay, clean_optimal_delay);
}
void RequiredDelayAtCorrectRange() {
for (int n = 0; n < 30; ++n) // Run clean and store delay.
Run(true);
int clean_optimal_delay = GetCurrentOptimalDelayMs();
// A relatively large delay.
const int kTargetDelayMs = (kInterarrivalJitterPacket + 10) *
kNum10msPerFrame * 10;
ASSERT_EQ(0, SetMinimumDelay(kTargetDelayMs));
for (int n = 0; n < 300; ++n) // Run enough iterations to fill the buffer.
Run(true);
Run(false); // Run with jitter.
int jittery_optimal_delay = GetCurrentOptimalDelayMs();
EXPECT_EQ(kTargetDelayMs, jittery_optimal_delay);
int required_delay = RequiredDelay();
// Checking |required_delay| is in correct range.
EXPECT_GT(required_delay, 0);
EXPECT_GT(jittery_optimal_delay, required_delay);
EXPECT_GT(required_delay, clean_optimal_delay);
// A tighter check for the value of |required_delay|.
// The jitter forces a delay of
// |kInterarrivalJitterPacket * kNum10msPerFrame * 10| milliseconds. So we
// expect |required_delay| be close to that.
EXPECT_NEAR(kInterarrivalJitterPacket * kNum10msPerFrame * 10,
required_delay, 1);
}
void TargetDelayBufferMinMax() {
const int kTargetMinDelayMs = kNum10msPerFrame * 10;
ASSERT_EQ(0, SetMinimumDelay(kTargetMinDelayMs));
for (int m = 0; m < 30; ++m) // Run enough iterations to fill the buffer.
Run(true);
int clean_optimal_delay = GetCurrentOptimalDelayMs();
EXPECT_EQ(kTargetMinDelayMs, clean_optimal_delay);
const int kTargetMaxDelayMs = 2 * (kNum10msPerFrame * 10);
ASSERT_EQ(0, SetMaximumDelay(kTargetMaxDelayMs));
for (int n = 0; n < 30; ++n) // Run enough iterations to fill the buffer.
Run(false);
int capped_optimal_delay = GetCurrentOptimalDelayMs();
EXPECT_EQ(kTargetMaxDelayMs, capped_optimal_delay);
}
private:
static const int kSampleRateHz = 16000;
static const int kNum10msPerFrame = 2;
static const size_t kFrameSizeSamples = 320; // 20 ms @ 16 kHz.
// payload-len = frame-samples * 2 bytes/sample.
static const int kPayloadLenBytes = 320 * 2;
// Inter-arrival time in number of packets in a jittery channel. One is no
// jitter.
static const int kInterarrivalJitterPacket = 2;
void Push() {
rtp_info_.header.timestamp += kFrameSizeSamples;
rtp_info_.header.sequenceNumber++;
ASSERT_EQ(0, acm_->IncomingPacket(payload_, kFrameSizeSamples * 2,
rtp_info_));
}
// Pull audio equivalent to the amount of audio in one RTP packet.
void Pull() {
AudioFrame frame;
for (int k = 0; k < kNum10msPerFrame; ++k) { // Pull one frame.
ASSERT_EQ(0, acm_->PlayoutData10Ms(-1, &frame));
// Had to use ASSERT_TRUE, ASSERT_EQ generated error.
ASSERT_TRUE(kSampleRateHz == frame.sample_rate_hz_);
ASSERT_EQ(1, frame.num_channels_);
ASSERT_TRUE(kSampleRateHz / 100 == frame.samples_per_channel_);
}
}
void Run(bool clean) {
for (int n = 0; n < 10; ++n) {
for (int m = 0; m < 5; ++m) {
Push();
Pull();
}
if (!clean) {
for (int m = 0; m < 10; ++m) { // Long enough to trigger delay change.
Push();
for (int n = 0; n < kInterarrivalJitterPacket; ++n)
Pull();
}
}
}
}
int SetMinimumDelay(int delay_ms) {
return acm_->SetMinimumPlayoutDelay(delay_ms);
}
int SetMaximumDelay(int delay_ms) {
return acm_->SetMaximumPlayoutDelay(delay_ms);
}
int GetCurrentOptimalDelayMs() {
NetworkStatistics stats;
acm_->GetNetworkStatistics(&stats);
return stats.preferredBufferSize;
}
int RequiredDelay() {
return acm_->LeastRequiredDelayMs();
}
rtc::scoped_ptr<AudioCodingModule> acm_;
WebRtcRTPHeader rtp_info_;
uint8_t payload_[kPayloadLenBytes];
};
TEST_F(TargetDelayTest, DISABLED_ON_ANDROID(OutOfRangeInput)) {
OutOfRangeInput();
}
TEST_F(TargetDelayTest, DISABLED_ON_ANDROID(NoTargetDelayBufferSizeChanges)) {
NoTargetDelayBufferSizeChanges();
}
TEST_F(TargetDelayTest, DISABLED_ON_ANDROID(WithTargetDelayBufferNotChanging)) {
WithTargetDelayBufferNotChanging();
}
TEST_F(TargetDelayTest, DISABLED_ON_ANDROID(RequiredDelayAtCorrectRange)) {
RequiredDelayAtCorrectRange();
}
TEST_F(TargetDelayTest, DISABLED_ON_ANDROID(TargetDelayBufferMinMax)) {
TargetDelayBufferMinMax();
}
} // namespace webrtc

View File

@ -0,0 +1,303 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "utility.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/common.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
#include "webrtc/modules/audio_coding/acm2/acm_common_defs.h"
#define NUM_CODECS_WITH_FIXED_PAYLOAD_TYPE 13
namespace webrtc {
ACMTestTimer::ACMTestTimer()
: _msec(0),
_sec(0),
_min(0),
_hour(0) {
return;
}
ACMTestTimer::~ACMTestTimer() {
return;
}
void ACMTestTimer::Reset() {
_msec = 0;
_sec = 0;
_min = 0;
_hour = 0;
return;
}
void ACMTestTimer::Tick10ms() {
_msec += 10;
Adjust();
return;
}
void ACMTestTimer::Tick1ms() {
_msec++;
Adjust();
return;
}
void ACMTestTimer::Tick100ms() {
_msec += 100;
Adjust();
return;
}
void ACMTestTimer::Tick1sec() {
_sec++;
Adjust();
return;
}
void ACMTestTimer::CurrentTimeHMS(char* currTime) {
sprintf(currTime, "%4lu:%02u:%06.3f", _hour, _min,
(double) _sec + (double) _msec / 1000.);
return;
}
void ACMTestTimer::CurrentTime(unsigned long& h, unsigned char& m,
unsigned char& s, unsigned short& ms) {
h = _hour;
m = _min;
s = _sec;
ms = _msec;
return;
}
void ACMTestTimer::Adjust() {
unsigned int n;
if (_msec >= 1000) {
n = _msec / 1000;
_msec -= (1000 * n);
_sec += n;
}
if (_sec >= 60) {
n = _sec / 60;
_sec -= (n * 60);
_min += n;
}
if (_min >= 60) {
n = _min / 60;
_min -= (n * 60);
_hour += n;
}
}
int16_t ChooseCodec(CodecInst& codecInst) {
PrintCodecs();
//AudioCodingModule* tmpACM = AudioCodingModule::Create(0);
uint8_t noCodec = AudioCodingModule::NumberOfCodecs();
int8_t codecID;
bool outOfRange = false;
char myStr[15] = "";
do {
printf("\nChoose a codec [0]: ");
EXPECT_TRUE(fgets(myStr, 10, stdin) != NULL);
codecID = atoi(myStr);
if ((codecID < 0) || (codecID >= noCodec)) {
printf("\nOut of range.\n");
outOfRange = true;
}
} while (outOfRange);
CHECK_ERROR(AudioCodingModule::Codec((uint8_t )codecID, &codecInst));
return 0;
}
void PrintCodecs() {
uint8_t noCodec = AudioCodingModule::NumberOfCodecs();
CodecInst codecInst;
printf("No Name [Hz] [bps]\n");
for (uint8_t codecCntr = 0; codecCntr < noCodec; codecCntr++) {
AudioCodingModule::Codec(codecCntr, &codecInst);
printf("%2d- %-18s %5d %6d\n", codecCntr, codecInst.plname,
codecInst.plfreq, codecInst.rate);
}
}
CircularBuffer::CircularBuffer(uint32_t len)
: _buff(NULL),
_idx(0),
_buffIsFull(false),
_calcAvg(false),
_calcVar(false),
_sum(0),
_sumSqr(0) {
_buff = new double[len];
if (_buff == NULL) {
_buffLen = 0;
} else {
for (uint32_t n = 0; n < len; n++) {
_buff[n] = 0;
}
_buffLen = len;
}
}
CircularBuffer::~CircularBuffer() {
if (_buff != NULL) {
delete[] _buff;
_buff = NULL;
}
}
void CircularBuffer::Update(const double newVal) {
assert(_buffLen > 0);
// store the value that is going to be overwritten
double oldVal = _buff[_idx];
// record the new value
_buff[_idx] = newVal;
// increment the index, to point to where we would
// write next
_idx++;
// it is a circular buffer, if we are at the end
// we have to cycle to the beginning
if (_idx >= _buffLen) {
// flag that the buffer is filled up.
_buffIsFull = true;
_idx = 0;
}
// Update
if (_calcAvg) {
// for the average we have to update
// the sum
_sum += (newVal - oldVal);
}
if (_calcVar) {
// to calculate variance we have to update
// the sum of squares
_sumSqr += (double) (newVal - oldVal) * (double) (newVal + oldVal);
}
}
void CircularBuffer::SetArithMean(bool enable) {
assert(_buffLen > 0);
if (enable && !_calcAvg) {
uint32_t lim;
if (_buffIsFull) {
lim = _buffLen;
} else {
lim = _idx;
}
_sum = 0;
for (uint32_t n = 0; n < lim; n++) {
_sum += _buff[n];
}
}
_calcAvg = enable;
}
void CircularBuffer::SetVariance(bool enable) {
assert(_buffLen > 0);
if (enable && !_calcVar) {
uint32_t lim;
if (_buffIsFull) {
lim = _buffLen;
} else {
lim = _idx;
}
_sumSqr = 0;
for (uint32_t n = 0; n < lim; n++) {
_sumSqr += _buff[n] * _buff[n];
}
}
_calcAvg = enable;
}
int16_t CircularBuffer::ArithMean(double& mean) {
assert(_buffLen > 0);
if (_buffIsFull) {
mean = _sum / (double) _buffLen;
return 0;
} else {
if (_idx > 0) {
mean = _sum / (double) _idx;
return 0;
} else {
return -1;
}
}
}
int16_t CircularBuffer::Variance(double& var) {
assert(_buffLen > 0);
if (_buffIsFull) {
var = _sumSqr / (double) _buffLen;
return 0;
} else {
if (_idx > 0) {
var = _sumSqr / (double) _idx;
return 0;
} else {
return -1;
}
}
}
bool FixedPayloadTypeCodec(const char* payloadName) {
char fixPayloadTypeCodecs[NUM_CODECS_WITH_FIXED_PAYLOAD_TYPE][32] = { "PCMU",
"PCMA", "GSM", "G723", "DVI4", "LPC", "PCMA", "G722", "QCELP", "CN",
"MPA", "G728", "G729" };
for (int n = 0; n < NUM_CODECS_WITH_FIXED_PAYLOAD_TYPE; n++) {
if (!STR_CASE_CMP(payloadName, fixPayloadTypeCodecs[n])) {
return true;
}
}
return false;
}
void VADCallback::Reset() {
memset(_numFrameTypes, 0, sizeof(_numFrameTypes));
}
VADCallback::VADCallback() {
memset(_numFrameTypes, 0, sizeof(_numFrameTypes));
}
void VADCallback::PrintFrameTypes() {
printf("kEmptyFrame......... %d\n", _numFrameTypes[kEmptyFrame]);
printf("kAudioFrameSpeech... %d\n", _numFrameTypes[kAudioFrameSpeech]);
printf("kAudioFrameCN....... %d\n", _numFrameTypes[kAudioFrameCN]);
printf("kVideoFrameKey...... %d\n", _numFrameTypes[kVideoFrameKey]);
printf("kVideoFrameDelta.... %d\n", _numFrameTypes[kVideoFrameDelta]);
}
int32_t VADCallback::InFrameType(FrameType frame_type) {
_numFrameTypes[frame_type]++;
return 0;
}
} // namespace webrtc

View File

@ -0,0 +1,139 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_UTILITY_H_
#define WEBRTC_MODULES_AUDIO_CODING_TEST_UTILITY_H_
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
namespace webrtc {
//-----------------------------
#define CHECK_ERROR(f) \
do { \
EXPECT_GE(f, 0) << "Error Calling API"; \
} while(0)
//-----------------------------
#define CHECK_PROTECTED(f) \
do { \
if (f >= 0) { \
ADD_FAILURE() << "Error Calling API"; \
} else { \
printf("An expected error is caught.\n"); \
} \
} while(0)
//----------------------------
#define CHECK_ERROR_MT(f) \
do { \
if (f < 0) { \
fprintf(stderr, "Error Calling API in file %s at line %d \n", \
__FILE__, __LINE__); \
} \
} while(0)
//----------------------------
#define CHECK_PROTECTED_MT(f) \
do { \
if (f >= 0) { \
fprintf(stderr, "Error Calling API in file %s at line %d \n", \
__FILE__, __LINE__); \
} else { \
printf("An expected error is caught.\n"); \
} \
} while(0)
#define DELETE_POINTER(p) \
do { \
if (p != NULL) { \
delete p; \
p = NULL; \
} \
} while(0)
class ACMTestTimer {
public:
ACMTestTimer();
~ACMTestTimer();
void Reset();
void Tick10ms();
void Tick1ms();
void Tick100ms();
void Tick1sec();
void CurrentTimeHMS(char* currTime);
void CurrentTime(unsigned long& h, unsigned char& m, unsigned char& s,
unsigned short& ms);
private:
void Adjust();
unsigned short _msec;
unsigned char _sec;
unsigned char _min;
unsigned long _hour;
};
class CircularBuffer {
public:
CircularBuffer(uint32_t len);
~CircularBuffer();
void SetArithMean(bool enable);
void SetVariance(bool enable);
void Update(const double newVal);
void IsBufferFull();
int16_t Variance(double& var);
int16_t ArithMean(double& mean);
protected:
double* _buff;
uint32_t _idx;
uint32_t _buffLen;
bool _buffIsFull;
bool _calcAvg;
bool _calcVar;
double _sum;
double _sumSqr;
};
int16_t ChooseCodec(CodecInst& codecInst);
void PrintCodecs();
bool FixedPayloadTypeCodec(const char* payloadName);
class VADCallback : public ACMVADCallback {
public:
VADCallback();
~VADCallback() {
}
int32_t InFrameType(FrameType frame_type);
void PrintFrameTypes();
void Reset();
private:
uint32_t _numFrameTypes[5];
};
void UseLegacyAcm(webrtc::Config* config);
void UseNewAcm(webrtc::Config* config);
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_UTILITY_H_