Using Rent-A-Codec for static Codec access in WVoE/MC.

Mostly moved code around in WebRtcVoiceEngine:
- Added new internal class WebRtcVoiceCodecs for static codec functions and the CodecPrefs.
- ConstructCodecs() -> WebRtcVoiceCodecs::SupportedCodecs().
- FindWebRtcCodec -> WebRtcVoiceCodecs::ToCodecInst().
- WebRtcVoiceMediaChannel::SetRecvCodecsInternal() folded into WebRtcVoiceMediaChannel::SetRecvCodecs() (slight logic change).
- Change to how SetRecPayloadType() is implemented in fakewebrtcvoiceengine.h (lines 460-470).

BUG=webrtc:4690

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

Cr-Commit-Position: refs/heads/master@{#10819}
This commit is contained in:
solenberg 2015-11-27 04:00:25 -08:00 committed by Commit bot
parent 8779a777f8
commit 26c8c91de2
4 changed files with 300 additions and 358 deletions

View File

@ -41,6 +41,7 @@
#include "webrtc/base/gunit.h"
#include "webrtc/base/stringutils.h"
#include "webrtc/config.h"
#include "webrtc/modules/audio_coding/acm2/rent_a_codec.h"
#include "webrtc/modules/audio_processing/include/audio_processing.h"
namespace cricket {
@ -63,18 +64,6 @@ static const int kOpusBandwidthFb = 20000;
#define WEBRTC_CHECK_CHANNEL(channel) \
if (channels_.find(channel) == channels_.end()) return -1;
#define WEBRTC_ASSERT_CHANNEL(channel) \
RTC_DCHECK(channels_.find(channel) != channels_.end());
// Verify the header extension ID, if enabled, is within the bounds specified in
// [RFC5285]: 1-14 inclusive.
#define WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id) \
do { \
if (enable && (id < 1 || id > 14)) { \
return -1; \
} \
} while (0);
class FakeAudioProcessing : public webrtc::AudioProcessing {
public:
FakeAudioProcessing() : experimental_ns_enabled_(false) {}
@ -189,6 +178,7 @@ class FakeWebRtcVoiceEngine
nack_max_packets(0),
send_ssrc(0),
associate_send_channel(-1),
recv_codecs(),
neteq_capacity(-1),
neteq_fast_accelerate(false) {
memset(&send_codec, 0, sizeof(send_codec));
@ -219,13 +209,10 @@ class FakeWebRtcVoiceEngine
bool neteq_fast_accelerate;
};
FakeWebRtcVoiceEngine(const cricket::AudioCodec* const* codecs,
int num_codecs)
FakeWebRtcVoiceEngine()
: inited_(false),
last_channel_(-1),
fail_create_channel_(false),
codecs_(codecs),
num_codecs_(num_codecs),
num_set_send_codecs_(0),
ec_enabled_(false),
ec_metrics_enabled_(false),
@ -247,12 +234,7 @@ class FakeWebRtcVoiceEngine
memset(&agc_config_, 0, sizeof(agc_config_));
}
~FakeWebRtcVoiceEngine() {
// Ought to have all been deleted by the WebRtcVoiceMediaChannel
// destructors, but just in case ...
for (std::map<int, Channel*>::const_iterator i = channels_.begin();
i != channels_.end(); ++i) {
delete i->second;
}
RTC_CHECK(channels_.empty());
}
bool ec_metrics_enabled() const { return ec_metrics_enabled_; }
@ -291,7 +273,7 @@ class FakeWebRtcVoiceEngine
return channels_[channel]->nack_max_packets;
}
const webrtc::PacketTime& GetLastRtpPacketTime(int channel) {
WEBRTC_ASSERT_CHANNEL(channel);
RTC_DCHECK(channels_.find(channel) != channels_.end());
return channels_[channel]->last_rtp_packet_time;
}
int GetSendCNPayloadType(int channel, bool wideband) {
@ -335,11 +317,8 @@ class FakeWebRtcVoiceEngine
return -1;
}
Channel* ch = new Channel();
for (int i = 0; i < NumOfCodecs(); ++i) {
webrtc::CodecInst codec;
GetCodec(i, codec);
ch->recv_codecs.push_back(codec);
}
auto db = webrtc::acm2::RentACodec::Database();
ch->recv_codecs.assign(db.begin(), db.end());
if (config.Get<webrtc::NetEqCapacityConfig>().enabled) {
ch->neteq_capacity = config.Get<webrtc::NetEqCapacityConfig>().capacity;
}
@ -439,22 +418,8 @@ class FakeWebRtcVoiceEngine
webrtc::RtcEventLog* GetEventLog() { return nullptr; }
// webrtc::VoECodec
WEBRTC_FUNC(NumOfCodecs, ()) {
return num_codecs_;
}
WEBRTC_FUNC(GetCodec, (int index, webrtc::CodecInst& codec)) {
if (index < 0 || index >= NumOfCodecs()) {
return -1;
}
const cricket::AudioCodec& c(*codecs_[index]);
codec.pltype = c.id;
rtc::strcpyn(codec.plname, sizeof(codec.plname), c.name.c_str());
codec.plfreq = c.clockrate;
codec.pacsize = 0;
codec.channels = c.channels;
codec.rate = c.bitrate;
return 0;
}
WEBRTC_STUB(NumOfCodecs, ());
WEBRTC_STUB(GetCodec, (int index, webrtc::CodecInst& codec));
WEBRTC_FUNC(SetSendCodec, (int channel, const webrtc::CodecInst& codec)) {
WEBRTC_CHECK_CHANNEL(channel);
// To match the behavior of the real implementation.
@ -492,16 +457,17 @@ class FakeWebRtcVoiceEngine
}
}
// Otherwise try to find this codec and update its payload type.
int result = -1; // not found
for (std::vector<webrtc::CodecInst>::iterator it = ch->recv_codecs.begin();
it != ch->recv_codecs.end(); ++it) {
if (strcmp(it->plname, codec.plname) == 0 &&
it->plfreq == codec.plfreq) {
it->plfreq == codec.plfreq &&
it->channels == codec.channels) {
it->pltype = codec.pltype;
it->channels = codec.channels;
return 0;
result = 0;
}
}
return -1; // not found
return result;
}
WEBRTC_FUNC(SetSendCNPayloadType, (int channel, int type,
webrtc::PayloadFrequencies frequency)) {
@ -932,8 +898,6 @@ class FakeWebRtcVoiceEngine
int last_channel_;
std::map<int, Channel*> channels_;
bool fail_create_channel_;
const cricket::AudioCodec* const* codecs_;
int num_codecs_;
int num_set_send_codecs_; // how many times we call SetSendCodec().
bool ec_enabled_;
bool ec_metrics_enabled_;
@ -957,8 +921,6 @@ class FakeWebRtcVoiceEngine
FakeAudioProcessing audio_processing_;
};
#undef WEBRTC_CHECK_HEADER_EXTENSION_ID
} // namespace cricket
#endif // TALK_SESSION_PHONE_FAKEWEBRTCVOICEENGINE_H_

View File

@ -53,6 +53,7 @@
#include "webrtc/base/stringutils.h"
#include "webrtc/call/rtc_event_log.h"
#include "webrtc/common.h"
#include "webrtc/modules/audio_coding/acm2/rent_a_codec.h"
#include "webrtc/modules/audio_processing/include/audio_processing.h"
#include "webrtc/system_wrappers/include/field_trial.h"
#include "webrtc/system_wrappers/include/trace.h"
@ -66,32 +67,6 @@ const int kDefaultTraceFilter = webrtc::kTraceNone | webrtc::kTraceTerseInfo |
const int kElevatedTraceFilter = kDefaultTraceFilter | webrtc::kTraceStateInfo |
webrtc::kTraceInfo;
const int kMaxNumPacketSize = 6;
struct CodecPref {
const char* name;
int clockrate;
int channels;
int payload_type;
bool is_multi_rate;
int packet_sizes_ms[kMaxNumPacketSize];
};
// Note: keep the supported packet sizes in ascending order.
const CodecPref kCodecPrefs[] = {
{ kOpusCodecName, 48000, 2, 111, true, { 10, 20, 40, 60 } },
{ kIsacCodecName, 16000, 1, 103, true, { 30, 60 } },
{ kIsacCodecName, 32000, 1, 104, true, { 30 } },
// G722 should be advertised as 8000 Hz because of the RFC "bug".
{ kG722CodecName, 8000, 1, 9, false, { 10, 20, 30, 40, 50, 60 } },
{ kIlbcCodecName, 8000, 1, 102, false, { 20, 30, 40, 60 } },
{ kPcmuCodecName, 8000, 1, 0, false, { 10, 20, 30, 40, 50, 60 } },
{ kPcmaCodecName, 8000, 1, 8, false, { 10, 20, 30, 40, 50, 60 } },
{ kCnCodecName, 32000, 1, 106, false, { } },
{ kCnCodecName, 16000, 1, 105, false, { } },
{ kCnCodecName, 8000, 1, 13, false, { } },
{ kRedCodecName, 8000, 1, 127, false, { } },
{ kDtmfCodecName, 8000, 1, 126, false, { } },
};
// For Linux/Mac, using the default device is done by specifying index 0 for
// VoE 4.0 and not -1 (which was the case for VoE 3.5).
//
@ -185,13 +160,6 @@ std::string ToString(const webrtc::CodecInst& codec) {
return ss.str();
}
void LogMultiline(rtc::LoggingSeverity sev, char* text) {
const char* delim = "\r\n";
for (char* tok = strtok(text, delim); tok; tok = strtok(NULL, delim)) {
LOG_V(sev) << tok;
}
}
bool IsCodec(const AudioCodec& codec, const char* ref_name) {
return (_stricmp(codec.name.c_str(), ref_name) == 0);
}
@ -200,19 +168,9 @@ bool IsCodec(const webrtc::CodecInst& codec, const char* ref_name) {
return (_stricmp(codec.plname, ref_name) == 0);
}
bool IsCodecMultiRate(const webrtc::CodecInst& codec) {
for (size_t i = 0; i < arraysize(kCodecPrefs); ++i) {
if (IsCodec(codec, kCodecPrefs[i].name) &&
kCodecPrefs[i].clockrate == codec.plfreq) {
return kCodecPrefs[i].is_multi_rate;
}
}
return false;
}
bool FindCodec(const std::vector<AudioCodec>& codecs,
const AudioCodec& codec,
AudioCodec* found_codec) {
const AudioCodec& codec,
AudioCodec* found_codec) {
for (const AudioCodec& c : codecs) {
if (c.Matches(codec)) {
if (found_codec != NULL) {
@ -242,38 +200,8 @@ bool IsNackEnabled(const AudioCodec& codec) {
kParamValueEmpty));
}
int SelectPacketSize(const CodecPref& codec_pref, int ptime_ms) {
int selected_packet_size_ms = codec_pref.packet_sizes_ms[0];
for (int packet_size_ms : codec_pref.packet_sizes_ms) {
if (packet_size_ms && packet_size_ms <= ptime_ms) {
selected_packet_size_ms = packet_size_ms;
}
}
return selected_packet_size_ms;
}
// If the AudioCodec param kCodecParamPTime is set, then we will set it to codec
// pacsize if it's valid, or we will pick the next smallest value we support.
// TODO(Brave): Query supported packet sizes from ACM when the API is ready.
bool SetPTimeAsPacketSize(webrtc::CodecInst* codec, int ptime_ms) {
for (const CodecPref& codec_pref : kCodecPrefs) {
if ((IsCodec(*codec, codec_pref.name) &&
codec_pref.clockrate == codec->plfreq) ||
IsCodec(*codec, kG722CodecName)) {
int packet_size_ms = SelectPacketSize(codec_pref, ptime_ms);
if (packet_size_ms) {
// Convert unit from milli-seconds to samples.
codec->pacsize = (codec->plfreq / 1000) * packet_size_ms;
return true;
}
}
}
return false;
}
// Return true if codec.params[feature] == "1", false otherwise.
bool IsCodecFeatureEnabled(const AudioCodec& codec,
const char* feature) {
bool IsCodecFeatureEnabled(const AudioCodec& codec, const char* feature) {
int value;
return codec.GetParam(feature, &value) && value == 1;
}
@ -340,18 +268,6 @@ void GetOpusConfig(const AudioCodec& codec, webrtc::CodecInst* voe_codec,
voe_codec->rate = GetOpusBitrate(codec, *max_playback_rate);
}
// Changes RTP timestamp rate of G722. This is due to the "bug" in the RFC
// which says that G722 should be advertised as 8 kHz although it is a 16 kHz
// codec.
void MaybeFixupG722(webrtc::CodecInst* voe_codec, int new_plfreq) {
if (IsCodec(*voe_codec, kG722CodecName)) {
// If the ASSERT triggers, the codec definition in WebRTC VoiceEngine
// has changed, and this special case is no longer needed.
RTC_DCHECK(voe_codec->plfreq != new_plfreq);
voe_codec->plfreq = new_plfreq;
}
}
// Gets the default set of options applied to the engine. Historically, these
// were supplied as a combination of flags from the channel manager (ec, agc,
// ns, and highpass) and the rest hardcoded in InitInternal.
@ -393,54 +309,17 @@ std::vector<webrtc::RtpExtension> FindAudioRtpHeaderExtensions(
}
return result;
}
} // namespace {
WebRtcVoiceEngine::WebRtcVoiceEngine()
: voe_wrapper_(new VoEWrapper()),
audio_state_(webrtc::AudioState::Create(MakeAudioStateConfig(voe()))) {
Construct();
}
WebRtcVoiceEngine::WebRtcVoiceEngine(VoEWrapper* voe_wrapper)
: voe_wrapper_(voe_wrapper) {
Construct();
}
void WebRtcVoiceEngine::Construct() {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
LOG(LS_VERBOSE) << "WebRtcVoiceEngine::WebRtcVoiceEngine";
signal_thread_checker_.DetachFromThread();
std::memset(&default_agc_config_, 0, sizeof(default_agc_config_));
webrtc::Trace::set_level_filter(kDefaultTraceFilter);
webrtc::Trace::SetTraceCallback(this);
// Load our audio codec list.
ConstructCodecs();
// Load our RTP Header extensions.
rtp_header_extensions_.push_back(
RtpHeaderExtension(kRtpAudioLevelHeaderExtension,
kRtpAudioLevelHeaderExtensionDefaultId));
rtp_header_extensions_.push_back(
RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension,
kRtpAbsoluteSenderTimeHeaderExtensionDefaultId));
if (webrtc::field_trial::FindFullName("WebRTC-SendSideBwe") == "Enabled") {
rtp_header_extensions_.push_back(RtpHeaderExtension(
kRtpTransportSequenceNumberHeaderExtension,
kRtpTransportSequenceNumberHeaderExtensionDefaultId));
}
options_ = GetDefaultEngineOptions();
}
void WebRtcVoiceEngine::ConstructCodecs() {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
LOG(LS_INFO) << "WebRtc VoiceEngine codecs:";
int ncodecs = voe_wrapper_->codec()->NumOfCodecs();
for (int i = 0; i < ncodecs; ++i) {
webrtc::CodecInst voe_codec;
if (GetVoeCodec(i, &voe_codec)) {
class WebRtcVoiceCodecs final {
public:
// TODO(solenberg): Do this filtering once off-line, add a simple AudioCodec
// list and add a test which verifies VoE supports the listed codecs.
static std::vector<AudioCodec> SupportedCodecs() {
LOG(LS_INFO) << "WebRtc VoiceEngine codecs:";
std::vector<AudioCodec> result;
for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) {
// Change the sample rate of G722 to 8000 to match SDP.
MaybeFixupG722(&voe_codec, 8000);
// Skip uncompressed formats.
if (IsCodec(voe_codec, kL16CodecName)) {
continue;
@ -483,24 +362,181 @@ void WebRtcVoiceEngine::ConstructCodecs() {
// TODO(hellner): Add ptime, sprop-stereo, and stereo
// when they can be set to values other than the default.
}
codecs_.push_back(codec);
result.push_back(codec);
} else {
LOG(LS_WARNING) << "Unexpected codec: " << ToString(voe_codec);
}
}
// Make sure they are in local preference order.
std::sort(result.begin(), result.end(), &AudioCodec::Preferable);
return result;
}
// Make sure they are in local preference order.
std::sort(codecs_.begin(), codecs_.end(), &AudioCodec::Preferable);
}
bool WebRtcVoiceEngine::GetVoeCodec(int index, webrtc::CodecInst* codec) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
if (voe_wrapper_->codec()->GetCodec(index, *codec) == -1) {
static bool ToCodecInst(const AudioCodec& in,
webrtc::CodecInst* out) {
for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) {
// Change the sample rate of G722 to 8000 to match SDP.
MaybeFixupG722(&voe_codec, 8000);
AudioCodec codec(voe_codec.pltype, voe_codec.plname, voe_codec.plfreq,
voe_codec.rate, voe_codec.channels, 0);
bool multi_rate = IsCodecMultiRate(voe_codec);
// Allow arbitrary rates for ISAC to be specified.
if (multi_rate) {
// Set codec.bitrate to 0 so the check for codec.Matches() passes.
codec.bitrate = 0;
}
if (codec.Matches(in)) {
if (out) {
// Fixup the payload type.
voe_codec.pltype = in.id;
// Set bitrate if specified.
if (multi_rate && in.bitrate != 0) {
voe_codec.rate = in.bitrate;
}
// Reset G722 sample rate to 16000 to match WebRTC.
MaybeFixupG722(&voe_codec, 16000);
// Apply codec-specific settings.
if (IsCodec(codec, kIsacCodecName)) {
// If ISAC and an explicit bitrate is not specified,
// enable auto bitrate adjustment.
voe_codec.rate = (in.bitrate > 0) ? in.bitrate : -1;
}
*out = voe_codec;
}
return true;
}
}
return false;
}
// Change the sample rate of G722 to 8000 to match SDP.
MaybeFixupG722(codec, 8000);
return true;
static bool IsCodecMultiRate(const webrtc::CodecInst& codec) {
for (size_t i = 0; i < arraysize(kCodecPrefs); ++i) {
if (IsCodec(codec, kCodecPrefs[i].name) &&
kCodecPrefs[i].clockrate == codec.plfreq) {
return kCodecPrefs[i].is_multi_rate;
}
}
return false;
}
// If the AudioCodec param kCodecParamPTime is set, then we will set it to
// codec pacsize if it's valid, or we will pick the next smallest value we
// support.
// TODO(Brave): Query supported packet sizes from ACM when the API is ready.
static bool SetPTimeAsPacketSize(webrtc::CodecInst* codec, int ptime_ms) {
for (const CodecPref& codec_pref : kCodecPrefs) {
if ((IsCodec(*codec, codec_pref.name) &&
codec_pref.clockrate == codec->plfreq) ||
IsCodec(*codec, kG722CodecName)) {
int packet_size_ms = SelectPacketSize(codec_pref, ptime_ms);
if (packet_size_ms) {
// Convert unit from milli-seconds to samples.
codec->pacsize = (codec->plfreq / 1000) * packet_size_ms;
return true;
}
}
}
return false;
}
private:
static const int kMaxNumPacketSize = 6;
struct CodecPref {
const char* name;
int clockrate;
int channels;
int payload_type;
bool is_multi_rate;
int packet_sizes_ms[kMaxNumPacketSize];
};
// Note: keep the supported packet sizes in ascending order.
static const CodecPref kCodecPrefs[12];
static int SelectPacketSize(const CodecPref& codec_pref, int ptime_ms) {
int selected_packet_size_ms = codec_pref.packet_sizes_ms[0];
for (int packet_size_ms : codec_pref.packet_sizes_ms) {
if (packet_size_ms && packet_size_ms <= ptime_ms) {
selected_packet_size_ms = packet_size_ms;
}
}
return selected_packet_size_ms;
}
// Changes RTP timestamp rate of G722. This is due to the "bug" in the RFC
// which says that G722 should be advertised as 8 kHz although it is a 16 kHz
// codec.
static void MaybeFixupG722(webrtc::CodecInst* voe_codec, int new_plfreq) {
if (IsCodec(*voe_codec, kG722CodecName)) {
// If the ASSERT triggers, the codec definition in WebRTC VoiceEngine
// has changed, and this special case is no longer needed.
RTC_DCHECK(voe_codec->plfreq != new_plfreq);
voe_codec->plfreq = new_plfreq;
}
}
};
const WebRtcVoiceCodecs::CodecPref WebRtcVoiceCodecs::kCodecPrefs[12] = {
{ kOpusCodecName, 48000, 2, 111, true, { 10, 20, 40, 60 } },
{ kIsacCodecName, 16000, 1, 103, true, { 30, 60 } },
{ kIsacCodecName, 32000, 1, 104, true, { 30 } },
// G722 should be advertised as 8000 Hz because of the RFC "bug".
{ kG722CodecName, 8000, 1, 9, false, { 10, 20, 30, 40, 50, 60 } },
{ kIlbcCodecName, 8000, 1, 102, false, { 20, 30, 40, 60 } },
{ kPcmuCodecName, 8000, 1, 0, false, { 10, 20, 30, 40, 50, 60 } },
{ kPcmaCodecName, 8000, 1, 8, false, { 10, 20, 30, 40, 50, 60 } },
{ kCnCodecName, 32000, 1, 106, false, { } },
{ kCnCodecName, 16000, 1, 105, false, { } },
{ kCnCodecName, 8000, 1, 13, false, { } },
{ kRedCodecName, 8000, 1, 127, false, { } },
{ kDtmfCodecName, 8000, 1, 126, false, { } },
};
} // namespace {
bool WebRtcVoiceEngine::ToCodecInst(const AudioCodec& in,
webrtc::CodecInst* out) {
return WebRtcVoiceCodecs::ToCodecInst(in, out);
}
WebRtcVoiceEngine::WebRtcVoiceEngine()
: voe_wrapper_(new VoEWrapper()),
audio_state_(webrtc::AudioState::Create(MakeAudioStateConfig(voe()))) {
Construct();
}
WebRtcVoiceEngine::WebRtcVoiceEngine(VoEWrapper* voe_wrapper)
: voe_wrapper_(voe_wrapper) {
Construct();
}
void WebRtcVoiceEngine::Construct() {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
LOG(LS_VERBOSE) << "WebRtcVoiceEngine::WebRtcVoiceEngine";
signal_thread_checker_.DetachFromThread();
std::memset(&default_agc_config_, 0, sizeof(default_agc_config_));
webrtc::Trace::set_level_filter(kDefaultTraceFilter);
webrtc::Trace::SetTraceCallback(this);
// Load our audio codec list.
codecs_ = WebRtcVoiceCodecs::SupportedCodecs();
// Load our RTP Header extensions.
rtp_header_extensions_.push_back(
RtpHeaderExtension(kRtpAudioLevelHeaderExtension,
kRtpAudioLevelHeaderExtensionDefaultId));
rtp_header_extensions_.push_back(
RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension,
kRtpAbsoluteSenderTimeHeaderExtensionDefaultId));
if (webrtc::field_trial::FindFullName("WebRTC-SendSideBwe") == "Enabled") {
rtp_header_extensions_.push_back(RtpHeaderExtension(
kRtpTransportSequenceNumberHeaderExtension,
kRtpTransportSequenceNumberHeaderExtensionDefaultId));
}
options_ = GetDefaultEngineOptions();
}
WebRtcVoiceEngine::~WebRtcVoiceEngine() {
@ -539,10 +575,15 @@ bool WebRtcVoiceEngine::InitInternal() {
webrtc::Trace::set_level_filter(kDefaultTraceFilter);
// Log the VoiceEngine version info
char buffer[1024] = "";
voe_wrapper_->base()->GetVersion(buffer);
LOG(LS_INFO) << "WebRtc VoiceEngine Version:";
LogMultiline(rtc::LS_INFO, buffer);
{
char buffer[1024] = "";
voe_wrapper_->base()->GetVersion(buffer);
LOG(LS_INFO) << "WebRtc VoiceEngine Version:";
const char* delim = "\r\n";
for (char* tok = strtok(buffer, delim); tok; tok = strtok(NULL, delim)) {
LOG(LS_INFO) << tok;
}
}
// Save the default AGC configuration settings. This must happen before
// calling SetOptions or the default will be overwritten.
@ -1056,55 +1097,6 @@ const std::vector<AudioCodec>& WebRtcVoiceEngine::codecs() {
return codecs_;
}
bool WebRtcVoiceEngine::FindCodec(const AudioCodec& in) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
return FindWebRtcCodec(in, NULL);
}
// Get the VoiceEngine codec that matches |in|, with the supplied settings.
bool WebRtcVoiceEngine::FindWebRtcCodec(const AudioCodec& in,
webrtc::CodecInst* out) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
int ncodecs = voe_wrapper_->codec()->NumOfCodecs();
for (int i = 0; i < ncodecs; ++i) {
webrtc::CodecInst voe_codec;
if (GetVoeCodec(i, &voe_codec)) {
AudioCodec codec(voe_codec.pltype, voe_codec.plname, voe_codec.plfreq,
voe_codec.rate, voe_codec.channels, 0);
bool multi_rate = IsCodecMultiRate(voe_codec);
// Allow arbitrary rates for ISAC to be specified.
if (multi_rate) {
// Set codec.bitrate to 0 so the check for codec.Matches() passes.
codec.bitrate = 0;
}
if (codec.Matches(in)) {
if (out) {
// Fixup the payload type.
voe_codec.pltype = in.id;
// Set bitrate if specified.
if (multi_rate && in.bitrate != 0) {
voe_codec.rate = in.bitrate;
}
// Reset G722 sample rate to 16000 to match WebRTC.
MaybeFixupG722(&voe_codec, 16000);
// Apply codec-specific settings.
if (IsCodec(codec, kIsacCodecName)) {
// If ISAC and an explicit bitrate is not specified,
// enable auto bitrate adjustment.
voe_codec.rate = (in.bitrate > 0) ? in.bitrate : -1;
}
*out = voe_codec;
}
return true;
}
}
}
return false;
}
const std::vector<RtpHeaderExtension>&
WebRtcVoiceEngine::rtp_header_extensions() const {
RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
@ -1592,7 +1584,26 @@ bool WebRtcVoiceMediaChannel::SetRecvCodecs(
PausePlayout();
}
bool result = SetRecvCodecsInternal(new_codecs);
bool result = true;
for (const AudioCodec& codec : new_codecs) {
webrtc::CodecInst voe_codec;
if (WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) {
LOG(LS_INFO) << ToString(codec);
voe_codec.pltype = codec.id;
for (const auto& ch : recv_streams_) {
if (engine()->voe()->codec()->SetRecPayloadType(
ch.second->channel(), voe_codec) == -1) {
LOG_RTCERR2(SetRecPayloadType, ch.second->channel(),
ToString(voe_codec));
result = false;
}
}
} else {
LOG(LS_WARNING) << "Unknown codec " << ToString(codec);
result = false;
break;
}
}
if (result) {
recv_codecs_ = codecs;
}
@ -1627,7 +1638,7 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
// Ignore codecs we don't know about. The negotiation step should prevent
// this, but double-check to be sure.
webrtc::CodecInst voe_codec;
if (!engine()->FindWebRtcCodec(codec, &voe_codec)) {
if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) {
LOG(LS_WARNING) << "Unknown codec " << ToString(codec);
continue;
}
@ -1668,7 +1679,7 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
// Set packet size if the AudioCodec param kCodecParamPTime is set.
int ptime_ms = 0;
if (codec.GetParam(kCodecParamPTime, &ptime_ms)) {
if (!SetPTimeAsPacketSize(&send_codec, ptime_ms)) {
if (!WebRtcVoiceCodecs::SetPTimeAsPacketSize(&send_codec, ptime_ms)) {
LOG(LS_WARNING) << "Failed to set packet size for codec "
<< send_codec.plname;
return false;
@ -1746,7 +1757,7 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
// Ignore codecs we don't know about. The negotiation step should prevent
// this, but double-check to be sure.
webrtc::CodecInst voe_codec;
if (!engine()->FindWebRtcCodec(codec, &voe_codec)) {
if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) {
LOG(LS_WARNING) << "Unknown codec " << ToString(codec);
continue;
}
@ -2116,24 +2127,20 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
}
// Turn off all supported codecs.
const int ncodecs = engine()->voe()->codec()->NumOfCodecs();
for (int i = 0; i < ncodecs; ++i) {
webrtc::CodecInst voe_codec;
if (engine()->voe()->codec()->GetCodec(i, voe_codec) != -1) {
voe_codec.pltype = -1;
if (engine()->voe()->codec()->SetRecPayloadType(
channel, voe_codec) == -1) {
LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
DeleteVoEChannel(channel);
return false;
}
// TODO(solenberg): Remove once "no codecs" is the default state of a stream.
for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) {
voe_codec.pltype = -1;
if (engine()->voe()->codec()->SetRecPayloadType(channel, voe_codec) == -1) {
LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
DeleteVoEChannel(channel);
return false;
}
}
// Only enable those configured for this channel.
for (const auto& codec : recv_codecs_) {
webrtc::CodecInst voe_codec;
if (engine()->FindWebRtcCodec(codec, &voe_codec)) {
if (WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) {
voe_codec.pltype = codec.id;
if (engine()->voe()->codec()->SetRecPayloadType(
channel, voe_codec) == -1) {
@ -2486,7 +2493,7 @@ bool WebRtcVoiceMediaChannel::SetSendBitrateInternal(int bps) {
return true;
webrtc::CodecInst codec = *send_codec_;
bool is_multi_rate = IsCodecMultiRate(codec);
bool is_multi_rate = WebRtcVoiceCodecs::IsCodecMultiRate(codec);
if (is_multi_rate) {
// If codec is multi-rate then just set the bitrate.
@ -2635,7 +2642,7 @@ bool WebRtcVoiceMediaChannel::GetRedSendCodec(const AudioCodec& red_codec,
if (codec.id == red_pt) {
// If we find the right codec, that will be the codec we pass to
// SetSendCodec, with the desired payload type.
if (engine()->FindWebRtcCodec(codec, send_codec)) {
if (WebRtcVoiceEngine::ToCodecInst(codec, send_codec)) {
return true;
} else {
break;
@ -2659,30 +2666,6 @@ bool WebRtcVoiceMediaChannel::SetPlayout(int channel, bool playout) {
}
return true;
}
bool WebRtcVoiceMediaChannel::SetRecvCodecsInternal(
const std::vector<AudioCodec>& new_codecs) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
for (const AudioCodec& codec : new_codecs) {
webrtc::CodecInst voe_codec;
if (engine()->FindWebRtcCodec(codec, &voe_codec)) {
LOG(LS_INFO) << ToString(codec);
voe_codec.pltype = codec.id;
for (const auto& ch : recv_streams_) {
if (engine()->voe()->codec()->SetRecPayloadType(
ch.second->channel(), voe_codec) == -1) {
LOG_RTCERR2(SetRecPayloadType, ch.second->channel(),
ToString(voe_codec));
return false;
}
}
} else {
LOG(LS_WARNING) << "Unknown codec " << ToString(codec);
return false;
}
}
return true;
}
} // namespace cricket
#endif // HAVE_WEBRTC_VOICE

View File

@ -57,8 +57,10 @@ class WebRtcVoiceMediaChannel;
// It uses the WebRtc VoiceEngine library for audio handling.
class WebRtcVoiceEngine final : public webrtc::TraceCallback {
friend class WebRtcVoiceMediaChannel;
public:
// Exposed for the WVoE/MC unit test.
static bool ToCodecInst(const AudioCodec& in, webrtc::CodecInst* out);
WebRtcVoiceEngine();
// Dependency injection for testing.
explicit WebRtcVoiceEngine(VoEWrapper* voe_wrapper);
@ -78,9 +80,6 @@ class WebRtcVoiceEngine final : public webrtc::TraceCallback {
int GetInputLevel();
const std::vector<AudioCodec>& codecs();
bool FindCodec(const AudioCodec& codec);
bool FindWebRtcCodec(const AudioCodec& codec, webrtc::CodecInst* gcodec);
const std::vector<RtpHeaderExtension>& rtp_header_extensions() const;
// For tracking WebRtc channels. Needed because we have to pause them
@ -114,8 +113,6 @@ class WebRtcVoiceEngine final : public webrtc::TraceCallback {
private:
void Construct();
void ConstructCodecs();
bool GetVoeCodec(int index, webrtc::CodecInst* codec);
bool InitInternal();
// Every option that is "set" will be applied. Every option not "set" will be
// ignored. This allows us to selectively turn on and off different options
@ -258,7 +255,6 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel,
}
bool SetSendCodecs(int channel, const std::vector<AudioCodec>& codecs);
bool SetSendBitrateInternal(int bps);
bool SetRecvCodecsInternal(const std::vector<AudioCodec>& new_codecs);
rtc::ThreadChecker worker_thread_checker_;

View File

@ -54,10 +54,6 @@ const cricket::AudioCodec kCn8000Codec(13, "CN", 8000, 0, 1, 0);
const cricket::AudioCodec kCn16000Codec(105, "CN", 16000, 0, 1, 0);
const cricket::AudioCodec kTelephoneEventCodec(106, "telephone-event", 8000, 0,
1, 0);
const cricket::AudioCodec* const kAudioCodecs[] = {
&kPcmuCodec, &kIsacCodec, &kOpusCodec, &kG722CodecVoE, &kRedCodec,
&kCn8000Codec, &kCn16000Codec, &kTelephoneEventCodec,
};
const uint32_t kSsrc1 = 0x99;
const uint32_t kSsrc2 = 0x98;
const uint32_t kSsrcs4[] = { 1, 2, 3, 4 };
@ -81,7 +77,6 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
public:
WebRtcVoiceEngineTestFake()
: call_(webrtc::Call::Config()),
voe_(kAudioCodecs, arraysize(kAudioCodecs)),
engine_(new FakeVoEWrapper(&voe_)),
channel_(nullptr) {
send_parameters_.codecs.push_back(kPcmuCodec);
@ -451,32 +446,33 @@ TEST_F(WebRtcVoiceEngineTestFake, FindCodec) {
cricket::AudioCodec codec;
webrtc::CodecInst codec_inst;
// Find PCMU with explicit clockrate and bitrate.
EXPECT_TRUE(engine_.FindWebRtcCodec(kPcmuCodec, &codec_inst));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(kPcmuCodec, &codec_inst));
// Find ISAC with explicit clockrate and 0 bitrate.
EXPECT_TRUE(engine_.FindWebRtcCodec(kIsacCodec, &codec_inst));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(kIsacCodec, &codec_inst));
// Find telephone-event with explicit clockrate and 0 bitrate.
EXPECT_TRUE(engine_.FindWebRtcCodec(kTelephoneEventCodec, &codec_inst));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(kTelephoneEventCodec,
&codec_inst));
// Find ISAC with a different payload id.
codec = kIsacCodec;
codec.id = 127;
EXPECT_TRUE(engine_.FindWebRtcCodec(codec, &codec_inst));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(codec, &codec_inst));
EXPECT_EQ(codec.id, codec_inst.pltype);
// Find PCMU with a 0 clockrate.
codec = kPcmuCodec;
codec.clockrate = 0;
EXPECT_TRUE(engine_.FindWebRtcCodec(codec, &codec_inst));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(codec, &codec_inst));
EXPECT_EQ(codec.id, codec_inst.pltype);
EXPECT_EQ(8000, codec_inst.plfreq);
// Find PCMU with a 0 bitrate.
codec = kPcmuCodec;
codec.bitrate = 0;
EXPECT_TRUE(engine_.FindWebRtcCodec(codec, &codec_inst));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(codec, &codec_inst));
EXPECT_EQ(codec.id, codec_inst.pltype);
EXPECT_EQ(64000, codec_inst.rate);
// Find ISAC with an explicit bitrate.
codec = kIsacCodec;
codec.bitrate = 32000;
EXPECT_TRUE(engine_.FindWebRtcCodec(codec, &codec_inst));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(codec, &codec_inst));
EXPECT_EQ(codec.id, codec_inst.pltype);
EXPECT_EQ(32000, codec_inst.rate);
}
@ -539,7 +535,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetRecvCodecsWithOpusNoStereo) {
cricket::StreamParams::CreateLegacy(kSsrc1)));
int channel_num = voe_.GetLastChannel();
webrtc::CodecInst opus;
engine_.FindWebRtcCodec(kOpusCodec, &opus);
cricket::WebRtcVoiceEngine::ToCodecInst(kOpusCodec, &opus);
// Even without stereo parameters, recv codecs still specify channels = 2.
EXPECT_EQ(2, opus.channels);
EXPECT_EQ(111, opus.pltype);
@ -562,7 +558,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetRecvCodecsWithOpus0Stereo) {
cricket::StreamParams::CreateLegacy(kSsrc1)));
int channel_num2 = voe_.GetLastChannel();
webrtc::CodecInst opus;
engine_.FindWebRtcCodec(kOpusCodec, &opus);
cricket::WebRtcVoiceEngine::ToCodecInst(kOpusCodec, &opus);
// Even when stereo is off, recv codecs still specify channels = 2.
EXPECT_EQ(2, opus.channels);
EXPECT_EQ(111, opus.pltype);
@ -585,7 +581,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetRecvCodecsWithOpus1Stereo) {
cricket::StreamParams::CreateLegacy(kSsrc1)));
int channel_num2 = voe_.GetLastChannel();
webrtc::CodecInst opus;
engine_.FindWebRtcCodec(kOpusCodec, &opus);
cricket::WebRtcVoiceEngine::ToCodecInst(kOpusCodec, &opus);
EXPECT_EQ(2, opus.channels);
EXPECT_EQ(111, opus.pltype);
EXPECT_STREQ("opus", opus.plname);
@ -670,7 +666,7 @@ TEST_F(WebRtcVoiceEngineTestFake, AddRecvCodecsWhilePlaying) {
int channel_num = voe_.GetLastChannel();
EXPECT_TRUE(voe_.GetPlayout(channel_num));
webrtc::CodecInst gcodec;
EXPECT_TRUE(engine_.FindWebRtcCodec(kOpusCodec, &gcodec));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(kOpusCodec, &gcodec));
EXPECT_EQ(kOpusCodec.id, gcodec.pltype);
}
@ -3246,54 +3242,60 @@ TEST(WebRtcVoiceEngineTest, StartupShutdown) {
// Tests that the library is configured with the codecs we want.
TEST(WebRtcVoiceEngineTest, HasCorrectCodecs) {
cricket::WebRtcVoiceEngine engine;
// Check codecs by name.
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(96, "OPUS", 48000, 0, 2, 0)));
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(96, "ISAC", 16000, 0, 1, 0)));
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(96, "ISAC", 32000, 0, 1, 0)));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(96, "OPUS", 48000, 0, 2, 0), nullptr));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(96, "ISAC", 16000, 0, 1, 0), nullptr));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(96, "ISAC", 32000, 0, 1, 0), nullptr));
// Check that name matching is case-insensitive.
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(96, "ILBC", 8000, 0, 1, 0)));
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(96, "iLBC", 8000, 0, 1, 0)));
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(96, "PCMU", 8000, 0, 1, 0)));
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(96, "PCMA", 8000, 0, 1, 0)));
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(96, "G722", 8000, 0, 1, 0)));
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(96, "red", 8000, 0, 1, 0)));
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(96, "CN", 32000, 0, 1, 0)));
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(96, "CN", 16000, 0, 1, 0)));
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(96, "CN", 8000, 0, 1, 0)));
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(96, "telephone-event", 8000, 0, 1, 0)));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(96, "ILBC", 8000, 0, 1, 0), nullptr));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(96, "iLBC", 8000, 0, 1, 0), nullptr));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(96, "PCMU", 8000, 0, 1, 0), nullptr));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(96, "PCMA", 8000, 0, 1, 0), nullptr));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(96, "G722", 8000, 0, 1, 0), nullptr));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(96, "red", 8000, 0, 1, 0), nullptr));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(96, "CN", 32000, 0, 1, 0), nullptr));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(96, "CN", 16000, 0, 1, 0), nullptr));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(96, "CN", 8000, 0, 1, 0), nullptr));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(96, "telephone-event", 8000, 0, 1, 0), nullptr));
// Check codecs with an id by id.
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(0, "", 8000, 0, 1, 0))); // PCMU
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(8, "", 8000, 0, 1, 0))); // PCMA
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(9, "", 8000, 0, 1, 0))); // G722
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(13, "", 8000, 0, 1, 0))); // CN
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(0, "", 8000, 0, 1, 0), nullptr)); // PCMU
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(8, "", 8000, 0, 1, 0), nullptr)); // PCMA
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(9, "", 8000, 0, 1, 0), nullptr)); // G722
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(13, "", 8000, 0, 1, 0), nullptr)); // CN
// Check sample/bitrate matching.
EXPECT_TRUE(engine.FindCodec(
cricket::AudioCodec(0, "PCMU", 8000, 64000, 1, 0)));
EXPECT_TRUE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(0, "PCMU", 8000, 64000, 1, 0), nullptr));
// Check that bad codecs fail.
EXPECT_FALSE(engine.FindCodec(cricket::AudioCodec(99, "ABCD", 0, 0, 1, 0)));
EXPECT_FALSE(engine.FindCodec(cricket::AudioCodec(88, "", 0, 0, 1, 0)));
EXPECT_FALSE(engine.FindCodec(cricket::AudioCodec(0, "", 0, 0, 2, 0)));
EXPECT_FALSE(engine.FindCodec(cricket::AudioCodec(0, "", 5000, 0, 1, 0)));
EXPECT_FALSE(engine.FindCodec(cricket::AudioCodec(0, "", 0, 5000, 1, 0)));
EXPECT_FALSE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(99, "ABCD", 0, 0, 1, 0), nullptr));
EXPECT_FALSE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(88, "", 0, 0, 1, 0), nullptr));
EXPECT_FALSE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(0, "", 0, 0, 2, 0), nullptr));
EXPECT_FALSE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(0, "", 5000, 0, 1, 0), nullptr));
EXPECT_FALSE(cricket::WebRtcVoiceEngine::ToCodecInst(
cricket::AudioCodec(0, "", 0, 5000, 1, 0), nullptr));
// Verify the payload id of common audio codecs, including CN, ISAC, and G722.
cricket::WebRtcVoiceEngine engine;
for (std::vector<cricket::AudioCodec>::const_iterator it =
engine.codecs().begin(); it != engine.codecs().end(); ++it) {
if (it->name == "CN" && it->clockrate == 16000) {
@ -3320,7 +3322,6 @@ TEST(WebRtcVoiceEngineTest, HasCorrectCodecs) {
EXPECT_EQ("1", it->params.find("useinbandfec")->second);
}
}
engine.Terminate();
}