Pass SdpAudioFormat through Channel, without converting to CodecInst
BUG=webrtc:5805
Review-Url: https://codereview.webrtc.org/2516993002
Cr-Commit-Position: refs/heads/master@{#16165}
diff --git a/webrtc/audio/audio_receive_stream.cc b/webrtc/audio/audio_receive_stream.cc
index f46337a..aaf77a8 100644
--- a/webrtc/audio/audio_receive_stream.cc
+++ b/webrtc/audio/audio_receive_stream.cc
@@ -101,6 +101,10 @@
channel_proxy_->RegisterExternalTransport(config.rtcp_send_transport);
+ for (const auto& kv : config.decoder_map) {
+ channel_proxy_->SetRecPayloadType(kv.first, kv.second);
+ }
+
for (const auto& extension : config.rtp.extensions) {
if (extension.uri == RtpExtension::kAudioLevelUri) {
channel_proxy_->SetReceiveAudioLevelIndicationStatus(true, extension.id);
diff --git a/webrtc/call/audio_receive_stream.h b/webrtc/call/audio_receive_stream.h
index 1299ded..3841672 100644
--- a/webrtc/call/audio_receive_stream.h
+++ b/webrtc/call/audio_receive_stream.h
@@ -102,11 +102,8 @@
// stream to one audio stream. Tracked by issue webrtc:4762.
std::string sync_group;
- // Decoders for every payload that we can receive. Call owns the
- // AudioDecoder instances once the Config is submitted to
- // Call::CreateReceiveStream().
- // TODO(solenberg): Use unique_ptr<> once our std lib fully supports C++11.
- std::map<uint8_t, AudioDecoder*> decoder_map;
+ // Decoder specifications for every payload type that we can receive.
+ std::map<int, SdpAudioFormat> decoder_map;
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory;
};
diff --git a/webrtc/media/engine/payload_type_mapper.cc b/webrtc/media/engine/payload_type_mapper.cc
index 0d449c4..496a39a 100644
--- a/webrtc/media/engine/payload_type_mapper.cc
+++ b/webrtc/media/engine/payload_type_mapper.cc
@@ -12,9 +12,14 @@
#include "webrtc/common_types.h"
#include "webrtc/media/base/mediaconstants.h"
+#include "webrtc/modules/audio_coding/codecs/audio_format.h"
namespace cricket {
+webrtc::SdpAudioFormat AudioCodecToSdpAudioFormat(const AudioCodec& ac) {
+ return webrtc::SdpAudioFormat(ac.name, ac.clockrate, ac.channels, ac.params);
+}
+
PayloadTypeMapper::PayloadTypeMapper()
// RFC 3551 reserves payload type numbers in the range 96-127 exclusively
// for dynamic assignment. Once those are used up, it is recommended that
diff --git a/webrtc/media/engine/payload_type_mapper.h b/webrtc/media/engine/payload_type_mapper.h
index a79fb47..248aace 100644
--- a/webrtc/media/engine/payload_type_mapper.h
+++ b/webrtc/media/engine/payload_type_mapper.h
@@ -20,6 +20,8 @@
namespace cricket {
+webrtc::SdpAudioFormat AudioCodecToSdpAudioFormat(const AudioCodec& ac);
+
class PayloadTypeMapper {
public:
PayloadTypeMapper();
diff --git a/webrtc/media/engine/webrtcvoiceengine.cc b/webrtc/media/engine/webrtcvoiceengine.cc
index e6fa12e..c23084e 100644
--- a/webrtc/media/engine/webrtcvoiceengine.cc
+++ b/webrtc/media/engine/webrtcvoiceengine.cc
@@ -1542,14 +1542,15 @@
RTC_DCHECK_GE(ch, 0);
RTC_DCHECK(call);
config_.rtp.remote_ssrc = remote_ssrc;
+ config_.rtp.local_ssrc = local_ssrc;
+ config_.rtp.transport_cc = use_transport_cc;
+ config_.rtp.nack.rtp_history_ms = use_nack ? kNackRtpHistoryMs : 0;
+ config_.rtp.extensions = extensions;
config_.rtcp_send_transport = rtcp_send_transport;
config_.voe_channel_id = ch;
config_.sync_group = sync_group;
config_.decoder_factory = decoder_factory;
- RecreateAudioReceiveStream(local_ssrc,
- use_transport_cc,
- use_nack,
- extensions);
+ RecreateAudioReceiveStream();
}
~WebRtcAudioReceiveStream() {
@@ -1559,27 +1560,40 @@
void RecreateAudioReceiveStream(uint32_t local_ssrc) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
- RecreateAudioReceiveStream(local_ssrc,
- config_.rtp.transport_cc,
- config_.rtp.nack.rtp_history_ms != 0,
- config_.rtp.extensions);
+ config_.rtp.local_ssrc = local_ssrc;
+ RecreateAudioReceiveStream();
}
void RecreateAudioReceiveStream(bool use_transport_cc, bool use_nack) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
- RecreateAudioReceiveStream(config_.rtp.local_ssrc,
- use_transport_cc,
- use_nack,
- config_.rtp.extensions);
+ config_.rtp.transport_cc = use_transport_cc;
+ config_.rtp.nack.rtp_history_ms = use_nack ? kNackRtpHistoryMs : 0;
+ RecreateAudioReceiveStream();
}
void RecreateAudioReceiveStream(
const std::vector<webrtc::RtpExtension>& extensions) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
- RecreateAudioReceiveStream(config_.rtp.local_ssrc,
- config_.rtp.transport_cc,
- config_.rtp.nack.rtp_history_ms != 0,
- extensions);
+ config_.rtp.extensions = extensions;
+ RecreateAudioReceiveStream();
+ }
+
+ // Set a new payload type -> decoder map. The new map must be a superset of
+ // the old one.
+ void RecreateAudioReceiveStream(
+ const std::map<int, webrtc::SdpAudioFormat>& decoder_map) {
+ RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
+ RTC_DCHECK([&] {
+ for (const auto& item : config_.decoder_map) {
+ auto it = decoder_map.find(item.first);
+ if (it == decoder_map.end() || *it != item) {
+ return false; // The old map isn't a subset of the new map.
+ }
+ }
+ return true;
+ }());
+ config_.decoder_map = decoder_map;
+ RecreateAudioReceiveStream();
}
webrtc::AudioReceiveStream::Stats GetStats() const {
@@ -1617,21 +1631,11 @@
}
private:
- void RecreateAudioReceiveStream(
- uint32_t local_ssrc,
- bool use_transport_cc,
- bool use_nack,
- const std::vector<webrtc::RtpExtension>& extensions) {
+ void RecreateAudioReceiveStream() {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
if (stream_) {
call_->DestroyAudioReceiveStream(stream_);
- stream_ = nullptr;
}
- config_.rtp.local_ssrc = local_ssrc;
- config_.rtp.transport_cc = use_transport_cc;
- config_.rtp.nack.rtp_history_ms = use_nack ? kNackRtpHistoryMs : 0;
- config_.rtp.extensions = extensions;
- RTC_DCHECK(!stream_);
stream_ = call_->CreateAudioReceiveStream(config_);
RTC_CHECK(stream_);
SetPlayout(playout_);
@@ -1901,40 +1905,34 @@
return true;
}
+ // Create a payload type -> SdpAudioFormat map with all the decoders. Fail
+ // unless the factory claims to support all decoders.
+ std::map<int, webrtc::SdpAudioFormat> decoder_map;
+ for (const AudioCodec& codec : codecs) {
+ auto format = AudioCodecToSdpAudioFormat(codec);
+ if (!IsCodec(codec, "cn") && !IsCodec(codec, "telephone-event") &&
+ !engine()->decoder_factory_->IsSupportedDecoder(format)) {
+ LOG(LS_ERROR) << "Unsupported codec: " << format;
+ return false;
+ }
+ decoder_map.insert({codec.id, std::move(format)});
+ }
+
if (playout_) {
// Receive codecs can not be changed while playing. So we temporarily
// pause playout.
ChangePlayout(false);
}
- bool result = true;
- for (const AudioCodec& codec : new_codecs) {
- webrtc::CodecInst voe_codec = {0};
- 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;
- }
+ for (auto& kv : recv_streams_) {
+ kv.second->RecreateAudioReceiveStream(decoder_map);
}
- if (result) {
- recv_codecs_ = codecs;
- }
+ recv_codecs_ = codecs;
if (desired_playout_ && !playout_) {
ChangePlayout(desired_playout_);
}
- return result;
+ return true;
}
// Utility function called from SetSendParameters() to extract current send
diff --git a/webrtc/media/engine/webrtcvoiceengine_unittest.cc b/webrtc/media/engine/webrtcvoiceengine_unittest.cc
index f15bde6..6038934 100644
--- a/webrtc/media/engine/webrtcvoiceengine_unittest.cc
+++ b/webrtc/media/engine/webrtcvoiceengine_unittest.cc
@@ -107,7 +107,6 @@
explicit WebRtcVoiceEngineTestFake(const char* field_trials)
: call_(webrtc::Call::Config(&event_log_)), voe_(&apm_),
override_field_trials_(field_trials) {
- auto factory = webrtc::MockAudioDecoderFactory::CreateUnusedFactory();
EXPECT_CALL(adm_, AddRef()).WillOnce(Return(0));
EXPECT_CALL(adm_, Release()).WillOnce(Return(0));
EXPECT_CALL(adm_, BuiltInAECIsAvailable()).WillOnce(Return(false));
@@ -116,8 +115,12 @@
EXPECT_CALL(apm_, ApplyConfig(testing::_));
EXPECT_CALL(apm_, SetExtraOptions(testing::_));
EXPECT_CALL(apm_, Initialize()).WillOnce(Return(0));
- engine_.reset(new cricket::WebRtcVoiceEngine(&adm_, factory, nullptr,
- new FakeVoEWrapper(&voe_)));
+ // TODO(kwiberg): We should use a mock AudioDecoderFactory, but a bunch of
+ // the tests here probe the specific set of codecs provided by the builtin
+ // factory. Those tests should probably be moved elsewhere.
+ engine_.reset(new cricket::WebRtcVoiceEngine(
+ &adm_, webrtc::CreateBuiltinAudioDecoderFactory(), nullptr,
+ new FakeVoEWrapper(&voe_)));
send_parameters_.codecs.push_back(kPcmuCodec);
recv_parameters_.codecs.push_back(kPcmuCodec);
}
@@ -873,14 +876,9 @@
parameters.codecs[0].id = 106; // collide with existing CN 32k
EXPECT_TRUE(channel_->SetRecvParameters(parameters));
- int channel_num2 = voe_.GetLastChannel();
- webrtc::CodecInst gcodec;
- rtc::strcpyn(gcodec.plname, arraysize(gcodec.plname), "ISAC");
- gcodec.plfreq = 16000;
- gcodec.channels = 1;
- EXPECT_EQ(0, voe_.GetRecPayloadType(channel_num2, gcodec));
- EXPECT_EQ(106, gcodec.pltype);
- EXPECT_STREQ("ISAC", gcodec.plname);
+ const auto& dm = GetRecvStreamConfig(kSsrc1).decoder_map;
+ ASSERT_EQ(1, dm.count(106));
+ EXPECT_EQ(webrtc::SdpAudioFormat("isac", 16000, 1), dm.at(106));
}
// Test that we can apply the same set of codecs again while playing.
diff --git a/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc b/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc
index be5e2c5..574b15d 100644
--- a/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc
+++ b/webrtc/modules/audio_coding/acm2/audio_coding_module_unittest.cc
@@ -1041,6 +1041,10 @@
std::vector<AudioCodecSpec> GetSupportedDecoders() override {
return fact_->GetSupportedDecoders();
}
+ bool IsSupportedDecoder(const SdpAudioFormat& format) override {
+ return format.name == "MockPCMu" ? true
+ : fact_->IsSupportedDecoder(format);
+ }
std::unique_ptr<AudioDecoder> MakeAudioDecoder(
const SdpAudioFormat& format) override {
return format.name == "MockPCMu" ? std::move(mock_decoder_)
diff --git a/webrtc/modules/audio_coding/acm2/rent_a_codec.cc b/webrtc/modules/audio_coding/acm2/rent_a_codec.cc
index 6787690..f0ed301 100644
--- a/webrtc/modules/audio_coding/acm2/rent_a_codec.cc
+++ b/webrtc/modules/audio_coding/acm2/rent_a_codec.cc
@@ -87,9 +87,7 @@
case NetEqDecoder::kDecoderG722_2ch:
return rtc::Optional<SdpAudioFormat>(SdpAudioFormat("g722", 8000, 2));
case NetEqDecoder::kDecoderOpus:
- return rtc::Optional<SdpAudioFormat>(
- SdpAudioFormat("opus", 48000, 2,
- std::map<std::string, std::string>{{"stereo", "0"}}));
+ return rtc::Optional<SdpAudioFormat>(SdpAudioFormat("opus", 48000, 2));
case NetEqDecoder::kDecoderOpus_2ch:
return rtc::Optional<SdpAudioFormat>(
SdpAudioFormat("opus", 48000, 2,
diff --git a/webrtc/modules/audio_coding/codecs/audio_decoder_factory.h b/webrtc/modules/audio_coding/codecs/audio_decoder_factory.h
index 93fca41..ca578f3 100644
--- a/webrtc/modules/audio_coding/codecs/audio_decoder_factory.h
+++ b/webrtc/modules/audio_coding/codecs/audio_decoder_factory.h
@@ -27,6 +27,8 @@
public:
virtual std::vector<AudioCodecSpec> GetSupportedDecoders() = 0;
+ virtual bool IsSupportedDecoder(const SdpAudioFormat& format) = 0;
+
virtual std::unique_ptr<AudioDecoder> MakeAudioDecoder(
const SdpAudioFormat& format) = 0;
};
diff --git a/webrtc/modules/audio_coding/codecs/audio_decoder_factory_unittest.cc b/webrtc/modules/audio_coding/codecs/audio_decoder_factory_unittest.cc
index 6b63f98..0379613 100644
--- a/webrtc/modules/audio_coding/codecs/audio_decoder_factory_unittest.cc
+++ b/webrtc/modules/audio_coding/codecs/audio_decoder_factory_unittest.cc
@@ -122,8 +122,8 @@
if (stereo != "XX") {
params["stereo"] = stereo;
}
- bool good =
- (hz == 48000 && channels == 2 && (stereo == "0" || stereo == "1"));
+ const bool good = (hz == 48000 && channels == 2 &&
+ (stereo == "XX" || stereo == "0" || stereo == "1"));
EXPECT_EQ(good, static_cast<bool>(adf->MakeAudioDecoder(SdpAudioFormat(
"opus", hz, channels, std::move(params)))));
}
diff --git a/webrtc/modules/audio_coding/codecs/audio_format.cc b/webrtc/modules/audio_coding/codecs/audio_format.cc
index ebd7cb0..88e42c5 100644
--- a/webrtc/modules/audio_coding/codecs/audio_format.cc
+++ b/webrtc/modules/audio_coding/codecs/audio_format.cc
@@ -22,14 +22,28 @@
int num_channels)
: name(name), clockrate_hz(clockrate_hz), num_channels(num_channels) {}
+SdpAudioFormat::SdpAudioFormat(const std::string& name,
+ int clockrate_hz,
+ int num_channels)
+ : name(name), clockrate_hz(clockrate_hz), num_channels(num_channels) {}
+
SdpAudioFormat::SdpAudioFormat(const char* name,
int clockrate_hz,
int num_channels,
- Parameters&& param)
+ const Parameters& param)
: name(name),
clockrate_hz(clockrate_hz),
num_channels(num_channels),
- parameters(std::move(param)) {}
+ parameters(param) {}
+
+SdpAudioFormat::SdpAudioFormat(const std::string& name,
+ int clockrate_hz,
+ int num_channels,
+ const Parameters& param)
+ : name(name),
+ clockrate_hz(clockrate_hz),
+ num_channels(num_channels),
+ parameters(param) {}
SdpAudioFormat::~SdpAudioFormat() = default;
SdpAudioFormat& SdpAudioFormat::operator=(const SdpAudioFormat&) = default;
diff --git a/webrtc/modules/audio_coding/codecs/audio_format.h b/webrtc/modules/audio_coding/codecs/audio_format.h
index 1199cc2..b3f803c 100644
--- a/webrtc/modules/audio_coding/codecs/audio_format.h
+++ b/webrtc/modules/audio_coding/codecs/audio_format.h
@@ -26,10 +26,15 @@
SdpAudioFormat(const SdpAudioFormat&);
SdpAudioFormat(SdpAudioFormat&&);
SdpAudioFormat(const char* name, int clockrate_hz, int num_channels);
+ SdpAudioFormat(const std::string& name, int clockrate_hz, int num_channels);
SdpAudioFormat(const char* name,
int clockrate_hz,
int num_channels,
- Parameters&& param);
+ const Parameters& param);
+ SdpAudioFormat(const std::string& name,
+ int clockrate_hz,
+ int num_channels,
+ const Parameters& param);
~SdpAudioFormat();
SdpAudioFormat& operator=(const SdpAudioFormat&);
diff --git a/webrtc/modules/audio_coding/codecs/audio_format_conversion.cc b/webrtc/modules/audio_coding/codecs/audio_format_conversion.cc
index ef9aa44..5d42409 100644
--- a/webrtc/modules/audio_coding/codecs/audio_format_conversion.cc
+++ b/webrtc/modules/audio_coding/codecs/audio_format_conversion.cc
@@ -10,21 +10,79 @@
#include "webrtc/modules/audio_coding/codecs/audio_format_conversion.h"
+#include <string.h>
+
+#include "webrtc/base/array_view.h"
#include "webrtc/base/checks.h"
+#include "webrtc/base/optional.h"
#include "webrtc/base/safe_conversions.h"
+#include "webrtc/base/sanitizer.h"
namespace webrtc {
+namespace {
+
+CodecInst MakeCodecInst(int payload_type,
+ const char* name,
+ int sample_rate,
+ int num_channels) {
+ // Create a CodecInst with some fields set. The remaining fields are zeroed,
+ // but we tell MSan to consider them uninitialized.
+ CodecInst ci = {0};
+ rtc::MsanMarkUninitialized(rtc::MakeArrayView(&ci, 1));
+ ci.pltype = payload_type;
+ strncpy(ci.plname, name, sizeof(ci.plname));
+ ci.plname[sizeof(ci.plname) - 1] = '\0';
+ ci.plfreq = sample_rate;
+ ci.channels = rtc::checked_cast<size_t>(num_channels);
+ return ci;
+}
+
+} // namespace
+
SdpAudioFormat CodecInstToSdp(const CodecInst& ci) {
- if (STR_CASE_CMP(ci.plname, "g722") == 0 && ci.plfreq == 16000) {
+ if (STR_CASE_CMP(ci.plname, "g722") == 0) {
+ RTC_CHECK_EQ(16000, ci.plfreq);
RTC_CHECK(ci.channels == 1 || ci.channels == 2);
return {"g722", 8000, static_cast<int>(ci.channels)};
- } else if (STR_CASE_CMP(ci.plname, "opus") == 0 && ci.plfreq == 48000) {
+ } else if (STR_CASE_CMP(ci.plname, "opus") == 0) {
+ RTC_CHECK_EQ(48000, ci.plfreq);
RTC_CHECK(ci.channels == 1 || ci.channels == 2);
- return {"opus", 48000, 2, {{"stereo", ci.channels == 1 ? "0" : "1"}}};
+ return ci.channels == 1
+ ? SdpAudioFormat("opus", 48000, 2)
+ : SdpAudioFormat("opus", 48000, 2, {{"stereo", "1"}});
} else {
return {ci.plname, ci.plfreq, rtc::checked_cast<int>(ci.channels)};
}
}
+CodecInst SdpToCodecInst(int payload_type, const SdpAudioFormat& audio_format) {
+ if (STR_CASE_CMP(audio_format.name.c_str(), "g722") == 0) {
+ RTC_CHECK_EQ(8000, audio_format.clockrate_hz);
+ RTC_CHECK(audio_format.num_channels == 1 || audio_format.num_channels == 2);
+ return MakeCodecInst(payload_type, "g722", 16000,
+ audio_format.num_channels);
+ } else if (STR_CASE_CMP(audio_format.name.c_str(), "opus") == 0) {
+ RTC_CHECK_EQ(48000, audio_format.clockrate_hz);
+ RTC_CHECK_EQ(2, audio_format.num_channels);
+ const int num_channels = [&] {
+ auto stereo = audio_format.parameters.find("stereo");
+ if (stereo != audio_format.parameters.end()) {
+ if (stereo->second == "0") {
+ return 1;
+ } else if (stereo->second == "1") {
+ return 2;
+ } else {
+ RTC_CHECK(false); // Bad stereo parameter.
+ }
+ }
+ return 1; // Default to mono.
+ }();
+ return MakeCodecInst(payload_type, "opus", 48000, num_channels);
+ } else {
+ return MakeCodecInst(payload_type, audio_format.name.c_str(),
+ audio_format.clockrate_hz, audio_format.num_channels);
+ }
+}
+
} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/audio_format_conversion.h b/webrtc/modules/audio_coding/codecs/audio_format_conversion.h
index ff71282..9267a52 100644
--- a/webrtc/modules/audio_coding/codecs/audio_format_conversion.h
+++ b/webrtc/modules/audio_coding/codecs/audio_format_conversion.h
@@ -17,6 +17,7 @@
namespace webrtc {
SdpAudioFormat CodecInstToSdp(const CodecInst& codec_inst);
+CodecInst SdpToCodecInst(int payload_type, const SdpAudioFormat& audio_format);
} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.cc b/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.cc
index 05b65c3..54ec776 100644
--- a/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.cc
+++ b/webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.cc
@@ -40,89 +40,133 @@
struct NamedDecoderConstructor {
const char* name;
- std::unique_ptr<AudioDecoder> (*constructor)(const SdpAudioFormat&);
-};
-std::unique_ptr<AudioDecoder> Unique(AudioDecoder* d) {
- return std::unique_ptr<AudioDecoder>(d);
-}
+ // If |format| is good, return true and (if |out| isn't null) reset |*out| to
+ // a new decoder object. If the |format| is not good, return false.
+ bool (*constructor)(const SdpAudioFormat& format,
+ std::unique_ptr<AudioDecoder>* out);
+};
// TODO(kwiberg): These factory functions should probably be moved to each
// decoder.
NamedDecoderConstructor decoder_constructors[] = {
{"pcmu",
- [](const SdpAudioFormat& format) {
- return format.clockrate_hz == 8000 && format.num_channels >= 1
- ? Unique(new AudioDecoderPcmU(format.num_channels))
- : nullptr;
+ [](const SdpAudioFormat& format, std::unique_ptr<AudioDecoder>* out) {
+ if (format.clockrate_hz == 8000 && format.num_channels >= 1) {
+ if (out) {
+ out->reset(new AudioDecoderPcmU(format.num_channels));
+ }
+ return true;
+ } else {
+ return false;
+ }
}},
{"pcma",
- [](const SdpAudioFormat& format) {
- return format.clockrate_hz == 8000 && format.num_channels >= 1
- ? Unique(new AudioDecoderPcmA(format.num_channels))
- : nullptr;
+ [](const SdpAudioFormat& format, std::unique_ptr<AudioDecoder>* out) {
+ if (format.clockrate_hz == 8000 && format.num_channels >= 1) {
+ if (out) {
+ out->reset(new AudioDecoderPcmA(format.num_channels));
+ }
+ return true;
+ } else {
+ return false;
+ }
}},
#ifdef WEBRTC_CODEC_ILBC
{"ilbc",
- [](const SdpAudioFormat& format) {
- return format.clockrate_hz == 8000 && format.num_channels == 1
- ? Unique(new AudioDecoderIlbc)
- : nullptr;
+ [](const SdpAudioFormat& format, std::unique_ptr<AudioDecoder>* out) {
+ if (format.clockrate_hz == 8000 && format.num_channels == 1) {
+ if (out) {
+ out->reset(new AudioDecoderIlbc);
+ }
+ return true;
+ } else {
+ return false;
+ }
}},
#endif
#if defined(WEBRTC_CODEC_ISACFX)
{"isac",
- [](const SdpAudioFormat& format) {
- return format.clockrate_hz == 16000 && format.num_channels == 1
- ? Unique(new AudioDecoderIsacFix(format.clockrate_hz))
- : nullptr;
+ [](const SdpAudioFormat& format, std::unique_ptr<AudioDecoder>* out) {
+ if (format.clockrate_hz == 16000 && format.num_channels == 1) {
+ if (out) {
+ out->reset(new AudioDecoderIsacFix(format.clockrate_hz));
+ }
+ return true;
+ } else {
+ return false;
+ }
}},
#elif defined(WEBRTC_CODEC_ISAC)
{"isac",
- [](const SdpAudioFormat& format) {
- return (format.clockrate_hz == 16000 || format.clockrate_hz == 32000) &&
- format.num_channels == 1
- ? Unique(new AudioDecoderIsac(format.clockrate_hz))
- : nullptr;
+ [](const SdpAudioFormat& format, std::unique_ptr<AudioDecoder>* out) {
+ if ((format.clockrate_hz == 16000 || format.clockrate_hz == 32000) &&
+ format.num_channels == 1) {
+ if (out) {
+ out->reset(new AudioDecoderIsac(format.clockrate_hz));
+ }
+ return true;
+ } else {
+ return false;
+ }
}},
#endif
{"l16",
- [](const SdpAudioFormat& format) {
- return format.num_channels >= 1
- ? Unique(new AudioDecoderPcm16B(format.clockrate_hz,
- format.num_channels))
- : nullptr;
+ [](const SdpAudioFormat& format, std::unique_ptr<AudioDecoder>* out) {
+ if (format.num_channels >= 1) {
+ if (out) {
+ out->reset(new AudioDecoderPcm16B(format.clockrate_hz,
+ format.num_channels));
+ }
+ return true;
+ } else {
+ return false;
+ }
}},
#ifdef WEBRTC_CODEC_G722
{"g722",
- [](const SdpAudioFormat& format) {
+ [](const SdpAudioFormat& format, std::unique_ptr<AudioDecoder>* out) {
if (format.clockrate_hz == 8000) {
- if (format.num_channels == 1)
- return Unique(new AudioDecoderG722);
- if (format.num_channels == 2)
- return Unique(new AudioDecoderG722Stereo);
+ if (format.num_channels == 1) {
+ if (out) {
+ out->reset(new AudioDecoderG722);
+ }
+ return true;
+ } else if (format.num_channels == 2) {
+ if (out) {
+ out->reset(new AudioDecoderG722Stereo);
+ }
+ return true;
+ }
}
- return Unique(nullptr);
+ return false;
}},
#endif
#ifdef WEBRTC_CODEC_OPUS
{"opus",
- [](const SdpAudioFormat& format) {
- rtc::Optional<int> num_channels = [&] {
+ [](const SdpAudioFormat& format, std::unique_ptr<AudioDecoder>* out) {
+ const rtc::Optional<int> num_channels = [&] {
auto stereo = format.parameters.find("stereo");
if (stereo != format.parameters.end()) {
if (stereo->second == "0") {
return rtc::Optional<int>(1);
} else if (stereo->second == "1") {
return rtc::Optional<int>(2);
+ } else {
+ return rtc::Optional<int>(); // Bad stereo parameter.
}
}
- return rtc::Optional<int>();
+ return rtc::Optional<int>(1); // Default to mono.
}();
- return format.clockrate_hz == 48000 && format.num_channels == 2 &&
- num_channels
- ? Unique(new AudioDecoderOpus(*num_channels))
- : nullptr;
+ if (format.clockrate_hz == 48000 && format.num_channels == 2 &&
+ num_channels) {
+ if (out) {
+ out->reset(new AudioDecoderOpus(*num_channels));
+ }
+ return true;
+ } else {
+ return false;
+ }
}},
#endif
};
@@ -140,37 +184,48 @@
},
#endif
#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
- { { "isac", 16000, 1 }, true },
+ {{"isac", 16000, 1}, true},
#endif
#if (defined(WEBRTC_CODEC_ISAC))
- { { "isac", 32000, 1 }, true },
+ {{"isac", 32000, 1}, true},
#endif
#ifdef WEBRTC_CODEC_G722
- { { "G722", 8000, 1 }, true },
+ {{"G722", 8000, 1}, true},
#endif
#ifdef WEBRTC_CODEC_ILBC
- { { "iLBC", 8000, 1 }, true },
+ {{"iLBC", 8000, 1}, true},
#endif
- { { "PCMU", 8000, 1 }, true },
- { { "PCMA", 8000, 1 }, true }
+ {{"PCMU", 8000, 1}, true},
+ {{"PCMA", 8000, 1}, true}
};
return specs;
}
+ bool IsSupportedDecoder(const SdpAudioFormat& format) override {
+ for (const auto& dc : decoder_constructors) {
+ if (STR_CASE_CMP(format.name.c_str(), dc.name) == 0) {
+ return dc.constructor(format, nullptr);
+ }
+ }
+ return false;
+ }
+
std::unique_ptr<AudioDecoder> MakeAudioDecoder(
const SdpAudioFormat& format) override {
for (const auto& dc : decoder_constructors) {
if (STR_CASE_CMP(format.name.c_str(), dc.name) == 0) {
- std::unique_ptr<AudioDecoder> dec = dc.constructor(format);
- if (dec) {
+ std::unique_ptr<AudioDecoder> decoder;
+ bool ok = dc.constructor(format, &decoder);
+ RTC_DCHECK_EQ(ok, decoder != nullptr);
+ if (decoder) {
const int expected_sample_rate_hz =
STR_CASE_CMP(format.name.c_str(), "g722") == 0
? 2 * format.clockrate_hz
: format.clockrate_hz;
- RTC_CHECK_EQ(expected_sample_rate_hz, dec->SampleRateHz());
+ RTC_CHECK_EQ(expected_sample_rate_hz, decoder->SampleRateHz());
}
- return dec;
+ return decoder;
}
}
return nullptr;
diff --git a/webrtc/modules/audio_coding/codecs/mock/mock_audio_decoder_factory.h b/webrtc/modules/audio_coding/codecs/mock/mock_audio_decoder_factory.h
index f2ef170..b988b85 100644
--- a/webrtc/modules/audio_coding/codecs/mock/mock_audio_decoder_factory.h
+++ b/webrtc/modules/audio_coding/codecs/mock/mock_audio_decoder_factory.h
@@ -15,6 +15,7 @@
#include "webrtc/base/scoped_ref_ptr.h"
#include "webrtc/modules/audio_coding/codecs/audio_decoder_factory.h"
+#include "webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.h"
#include "webrtc/test/gmock.h"
namespace webrtc {
@@ -22,6 +23,7 @@
class MockAudioDecoderFactory : public AudioDecoderFactory {
public:
MOCK_METHOD0(GetSupportedDecoders, std::vector<AudioCodecSpec>());
+ MOCK_METHOD1(IsSupportedDecoder, bool(const SdpAudioFormat&));
std::unique_ptr<AudioDecoder> MakeAudioDecoder(
const SdpAudioFormat& format) {
std::unique_ptr<AudioDecoder> return_value;
@@ -46,6 +48,8 @@
ON_CALL(*factory.get(), GetSupportedDecoders())
.WillByDefault(Return(std::vector<webrtc::AudioCodecSpec>()));
EXPECT_CALL(*factory.get(), GetSupportedDecoders()).Times(AnyNumber());
+ ON_CALL(*factory, IsSupportedDecoder(_)).WillByDefault(Return(false));
+ EXPECT_CALL(*factory, IsSupportedDecoder(_)).Times(AnyNumber());
EXPECT_CALL(*factory.get(), MakeAudioDecoderMock(_, _)).Times(0);
return factory;
}
@@ -65,6 +69,8 @@
ON_CALL(*factory.get(), GetSupportedDecoders())
.WillByDefault(Return(std::vector<webrtc::AudioCodecSpec>()));
EXPECT_CALL(*factory.get(), GetSupportedDecoders()).Times(AnyNumber());
+ ON_CALL(*factory, IsSupportedDecoder(_)).WillByDefault(Return(false));
+ EXPECT_CALL(*factory, IsSupportedDecoder(_)).Times(AnyNumber());
ON_CALL(*factory.get(), MakeAudioDecoderMock(_, _))
.WillByDefault(SetArgPointee<1>(nullptr));
EXPECT_CALL(*factory.get(), MakeAudioDecoderMock(_, _)).Times(AnyNumber());
diff --git a/webrtc/tools/BUILD.gn b/webrtc/tools/BUILD.gn
index 6dc3708..b1e603c 100644
--- a/webrtc/tools/BUILD.gn
+++ b/webrtc/tools/BUILD.gn
@@ -205,6 +205,9 @@
"../call:call_interfaces",
"../logging:rtc_event_log_impl",
"../logging:rtc_event_log_parser",
+
+ # TODO(kwiberg): Remove this dependency.
+ "../modules/audio_coding:audio_format",
"../modules/congestion_controller",
"../modules/rtp_rtcp",
"../system_wrappers:system_wrappers_default",
diff --git a/webrtc/voice_engine/channel.cc b/webrtc/voice_engine/channel.cc
index 68f2e2d..5231691 100644
--- a/webrtc/voice_engine/channel.cc
+++ b/webrtc/voice_engine/channel.cc
@@ -1372,6 +1372,11 @@
}
int32_t Channel::SetRecPayloadType(const CodecInst& codec) {
+ return SetRecPayloadType(codec.pltype, CodecInstToSdp(codec));
+}
+
+int32_t Channel::SetRecPayloadType(int payload_type,
+ const SdpAudioFormat& format) {
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
"Channel::SetRecPayloadType()");
@@ -1382,7 +1387,22 @@
return -1;
}
- if (codec.pltype == -1) {
+ const CodecInst codec = [&] {
+ CodecInst c = SdpToCodecInst(payload_type, format);
+
+ // Bug 6986: Emulate an old bug that caused us to always choose to decode
+ // Opus in stereo. To be able to remove this, we first need to fix the
+ // other half of bug 6986, which is about losing the Opus "stereo"
+ // parameter.
+ // TODO(kwiberg): Remove this special case, a.k.a. fix bug 6986.
+ if (STR_CASE_CMP(codec.plname, "opus") == 0) {
+ c.channels = 2;
+ }
+
+ return c;
+ }();
+
+ if (payload_type == -1) {
// De-register the selected codec (RTP/RTCP module and ACM)
int8_t pltype(-1);
@@ -1420,11 +1440,9 @@
return -1;
}
}
- if (!audio_coding_->RegisterReceiveCodec(codec.pltype,
- CodecInstToSdp(codec))) {
- audio_coding_->UnregisterReceiveCodec(codec.pltype);
- if (!audio_coding_->RegisterReceiveCodec(codec.pltype,
- CodecInstToSdp(codec))) {
+ if (!audio_coding_->RegisterReceiveCodec(payload_type, format)) {
+ audio_coding_->UnregisterReceiveCodec(payload_type);
+ if (!audio_coding_->RegisterReceiveCodec(payload_type, format)) {
_engineStatisticsPtr->SetLastError(
VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
"SetRecPayloadType() ACM registration failed - 1");
diff --git a/webrtc/voice_engine/channel.h b/webrtc/voice_engine/channel.h
index d2b24a2..62adc5b 100644
--- a/webrtc/voice_engine/channel.h
+++ b/webrtc/voice_engine/channel.h
@@ -196,6 +196,7 @@
int32_t SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX);
int32_t GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX);
int32_t SetRecPayloadType(const CodecInst& codec);
+ int32_t SetRecPayloadType(int payload_type, const SdpAudioFormat& format);
int32_t GetRecPayloadType(CodecInst& codec);
int32_t SetSendCNPayloadType(int type, PayloadFrequencies frequency);
int SetOpusMaxPlaybackRate(int frequency_hz);
diff --git a/webrtc/voice_engine/channel_proxy.cc b/webrtc/voice_engine/channel_proxy.cc
index 2dd74fa..59b920f 100644
--- a/webrtc/voice_engine/channel_proxy.cc
+++ b/webrtc/voice_engine/channel_proxy.cc
@@ -153,6 +153,13 @@
channel()->SetBitRate(bitrate_bps, probing_interval_ms);
}
+void ChannelProxy::SetRecPayloadType(int payload_type,
+ const SdpAudioFormat& format) {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ const int result = channel()->SetRecPayloadType(payload_type, format);
+ RTC_DCHECK_EQ(0, result);
+}
+
void ChannelProxy::SetSink(std::unique_ptr<AudioSinkInterface> sink) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
channel()->SetSink(std::move(sink));
diff --git a/webrtc/voice_engine/channel_proxy.h b/webrtc/voice_engine/channel_proxy.h
index 8a78069..4bd76a4 100644
--- a/webrtc/voice_engine/channel_proxy.h
+++ b/webrtc/voice_engine/channel_proxy.h
@@ -74,6 +74,8 @@
int payload_frequency);
virtual bool SendTelephoneEventOutband(int event, int duration_ms);
virtual void SetBitrate(int bitrate_bps, int64_t probing_interval_ms);
+ virtual void SetRecPayloadType(int payload_type,
+ const SdpAudioFormat& format);
virtual void SetSink(std::unique_ptr<AudioSinkInterface> sink);
virtual void SetInputMute(bool muted);
virtual void RegisterExternalTransport(Transport* transport);