diff --git a/webrtc/api/audio_codecs/g711/BUILD.gn b/webrtc/api/audio_codecs/g711/BUILD.gn new file mode 100644 index 0000000000..fbf9248683 --- /dev/null +++ b/webrtc/api/audio_codecs/g711/BUILD.gn @@ -0,0 +1,39 @@ +# Copyright (c) 2017 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. + +import("../../../webrtc.gni") +if (is_android) { + import("//build/config/android/config.gni") + import("//build/config/android/rules.gni") +} + +rtc_static_library("audio_encoder_g711") { + sources = [ + "audio_encoder_g711.cc", + "audio_encoder_g711.h", + ] + deps = [ + "..:audio_codecs_api", + "../../..:webrtc_common", + "../../../modules/audio_coding:g711", + "../../../rtc_base:rtc_base_approved", + ] +} + +rtc_static_library("audio_decoder_g711") { + sources = [ + "audio_decoder_g711.cc", + "audio_decoder_g711.h", + ] + deps = [ + "..:audio_codecs_api", + "../../..:webrtc_common", + "../../../modules/audio_coding:g711", + "../../../rtc_base:rtc_base_approved", + ] +} diff --git a/webrtc/api/audio_codecs/g711/audio_decoder_g711.cc b/webrtc/api/audio_codecs/g711/audio_decoder_g711.cc new file mode 100644 index 0000000000..cb4b074fee --- /dev/null +++ b/webrtc/api/audio_codecs/g711/audio_decoder_g711.cc @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017 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/api/audio_codecs/g711/audio_decoder_g711.h" + +#include +#include + +#include "webrtc/common_types.h" +#include "webrtc/modules/audio_coding/codecs/g711/audio_decoder_pcm.h" +#include "webrtc/rtc_base/ptr_util.h" +#include "webrtc/rtc_base/safe_conversions.h" + +namespace webrtc { + +rtc::Optional AudioDecoderG711::SdpToConfig( + const SdpAudioFormat& format) { + const bool is_pcmu = STR_CASE_CMP(format.name.c_str(), "PCMU") == 0; + const bool is_pcma = STR_CASE_CMP(format.name.c_str(), "PCMA") == 0; + if (format.clockrate_hz == 8000 && format.num_channels >= 1 && + (is_pcmu || is_pcma)) { + Config config; + config.type = is_pcmu ? Config::Type::kPcmU : Config::Type::kPcmA; + config.num_channels = rtc::dchecked_cast(format.num_channels); + RTC_DCHECK(config.IsOk()); + return rtc::Optional(config); + } else { + return rtc::Optional(); + } +} + +void AudioDecoderG711::AppendSupportedDecoders( + std::vector* specs) { + for (const char* type : {"PCMU", "PCMA"}) { + specs->push_back({{type, 8000, 1}, {8000, 1, 64000}}); + } +} + +std::unique_ptr AudioDecoderG711::MakeAudioDecoder( + const Config& config) { + RTC_DCHECK(config.IsOk()); + switch (config.type) { + case Config::Type::kPcmU: + return rtc::MakeUnique(config.num_channels); + case Config::Type::kPcmA: + return rtc::MakeUnique(config.num_channels); + default: + return nullptr; + } +} + +} // namespace webrtc diff --git a/webrtc/api/audio_codecs/g711/audio_decoder_g711.h b/webrtc/api/audio_codecs/g711/audio_decoder_g711.h new file mode 100644 index 0000000000..b9650c95a6 --- /dev/null +++ b/webrtc/api/audio_codecs/g711/audio_decoder_g711.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017 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_API_AUDIO_CODECS_G711_AUDIO_DECODER_G711_H_ +#define WEBRTC_API_AUDIO_CODECS_G711_AUDIO_DECODER_G711_H_ + +#include +#include + +#include "webrtc/api/audio_codecs/audio_decoder.h" +#include "webrtc/api/audio_codecs/audio_format.h" +#include "webrtc/rtc_base/optional.h" + +namespace webrtc { + +// G711 decoder API for use as a template parameter to +// CreateAudioDecoderFactory<...>(). +// +// NOTE: This struct is still under development and may change without notice. +struct AudioDecoderG711 { + struct Config { + enum class Type { kPcmU, kPcmA }; + bool IsOk() const { + return (type == Type::kPcmU || type == Type::kPcmA) && num_channels >= 1; + } + Type type; + int num_channels; + }; + static rtc::Optional SdpToConfig(const SdpAudioFormat& audio_format); + static void AppendSupportedDecoders(std::vector* specs); + static std::unique_ptr MakeAudioDecoder(const Config& config); +}; + +} // namespace webrtc + +#endif // WEBRTC_API_AUDIO_CODECS_G711_AUDIO_DECODER_G711_H_ diff --git a/webrtc/api/audio_codecs/g711/audio_encoder_g711.cc b/webrtc/api/audio_codecs/g711/audio_encoder_g711.cc new file mode 100644 index 0000000000..28fb951409 --- /dev/null +++ b/webrtc/api/audio_codecs/g711/audio_encoder_g711.cc @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017 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/api/audio_codecs/g711/audio_encoder_g711.h" + +#include +#include + +#include "webrtc/common_types.h" +#include "webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.h" +#include "webrtc/rtc_base/ptr_util.h" +#include "webrtc/rtc_base/safe_conversions.h" +#include "webrtc/rtc_base/safe_minmax.h" +#include "webrtc/rtc_base/string_to_number.h" + +namespace webrtc { + +rtc::Optional AudioEncoderG711::SdpToConfig( + const SdpAudioFormat& format) { + const bool is_pcmu = STR_CASE_CMP(format.name.c_str(), "PCMU") == 0; + const bool is_pcma = STR_CASE_CMP(format.name.c_str(), "PCMA") == 0; + if (format.clockrate_hz == 8000 && format.num_channels >= 1 && + (is_pcmu || is_pcma)) { + Config config; + config.type = is_pcmu ? Config::Type::kPcmU : Config::Type::kPcmA; + config.num_channels = rtc::dchecked_cast(format.num_channels); + config.frame_size_ms = 20; + auto ptime_iter = format.parameters.find("ptime"); + if (ptime_iter != format.parameters.end()) { + const auto ptime = rtc::StringToNumber(ptime_iter->second); + if (ptime && *ptime > 0) { + config.frame_size_ms = rtc::SafeClamp(10 * (*ptime / 10), 10, 60); + } + } + RTC_DCHECK(config.IsOk()); + return rtc::Optional(config); + } else { + return rtc::Optional(); + } +} + +void AudioEncoderG711::AppendSupportedEncoders( + std::vector* specs) { + for (const char* type : {"PCMU", "PCMA"}) { + specs->push_back({{type, 8000, 1}, {8000, 1, 64000}}); + } +} + +AudioCodecInfo AudioEncoderG711::QueryAudioEncoder(const Config& config) { + RTC_DCHECK(config.IsOk()); + return {8000, rtc::dchecked_cast(config.num_channels), + 64000 * config.num_channels}; +} + +std::unique_ptr AudioEncoderG711::MakeAudioEncoder( + const Config& config, + int payload_type) { + RTC_DCHECK(config.IsOk()); + switch (config.type) { + case Config::Type::kPcmU: { + AudioEncoderPcmU::Config impl_config; + impl_config.num_channels = config.num_channels; + impl_config.frame_size_ms = config.frame_size_ms; + impl_config.payload_type = payload_type; + return rtc::MakeUnique(impl_config); + } + case Config::Type::kPcmA: { + AudioEncoderPcmA::Config impl_config; + impl_config.num_channels = config.num_channels; + impl_config.frame_size_ms = config.frame_size_ms; + impl_config.payload_type = payload_type; + return rtc::MakeUnique(impl_config); + } + default: { return nullptr; } + } +} + +} // namespace webrtc diff --git a/webrtc/api/audio_codecs/g711/audio_encoder_g711.h b/webrtc/api/audio_codecs/g711/audio_encoder_g711.h new file mode 100644 index 0000000000..a22650dd44 --- /dev/null +++ b/webrtc/api/audio_codecs/g711/audio_encoder_g711.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017 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_API_AUDIO_CODECS_G711_AUDIO_ENCODER_G711_H_ +#define WEBRTC_API_AUDIO_CODECS_G711_AUDIO_ENCODER_G711_H_ + +#include +#include + +#include "webrtc/api/audio_codecs/audio_encoder.h" +#include "webrtc/api/audio_codecs/audio_format.h" +#include "webrtc/rtc_base/optional.h" + +namespace webrtc { + +// G711 encoder API for use as a template parameter to +// CreateAudioEncoderFactory<...>(). +// +// NOTE: This struct is still under development and may change without notice. +struct AudioEncoderG711 { + struct Config { + enum class Type { kPcmU, kPcmA }; + bool IsOk() const { + return (type == Type::kPcmU || type == Type::kPcmA) && + frame_size_ms > 0 && frame_size_ms % 10 == 0 && num_channels >= 1; + } + Type type = Type::kPcmU; + int num_channels = 1; + int frame_size_ms = 20; + }; + static rtc::Optional SdpToConfig( + const SdpAudioFormat& audio_format); + static void AppendSupportedEncoders(std::vector* specs); + static AudioCodecInfo QueryAudioEncoder(const Config& config); + static std::unique_ptr MakeAudioEncoder(const Config& config, + int payload_type); +}; + +} // namespace webrtc + +#endif // WEBRTC_API_AUDIO_CODECS_G711_AUDIO_ENCODER_G711_H_ diff --git a/webrtc/api/audio_codecs/test/BUILD.gn b/webrtc/api/audio_codecs/test/BUILD.gn index 4a0c878920..83ea44e2f5 100644 --- a/webrtc/api/audio_codecs/test/BUILD.gn +++ b/webrtc/api/audio_codecs/test/BUILD.gn @@ -25,6 +25,8 @@ if (rtc_include_tests) { "../../../rtc_base:rtc_base_approved", "../../../test:audio_codec_mocks", "../../../test:test_support", + "../g711:audio_decoder_g711", + "../g711:audio_encoder_g711", "../g722:audio_decoder_g722", "../g722:audio_encoder_g722", "../ilbc:audio_decoder_ilbc", diff --git a/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc b/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc index 9b2747cd61..ee754d4a9b 100644 --- a/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc +++ b/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc @@ -9,6 +9,7 @@ */ #include "webrtc/api/audio_codecs/audio_decoder_factory_template.h" +#include "webrtc/api/audio_codecs/g711/audio_decoder_g711.h" #include "webrtc/api/audio_codecs/g722/audio_decoder_g722.h" #include "webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.h" #include "webrtc/api/audio_codecs/opus/audio_decoder_opus.h" @@ -113,6 +114,24 @@ TEST(AudioDecoderFactoryTemplateTest, TwoDecoderTypes) { EXPECT_EQ(16000, dec2->SampleRateHz()); } +TEST(AudioDecoderFactoryTemplateTest, G711) { + auto factory = CreateAudioDecoderFactory(); + EXPECT_THAT(factory->GetSupportedDecoders(), + testing::ElementsAre( + AudioCodecSpec{{"PCMU", 8000, 1}, {8000, 1, 64000}}, + AudioCodecSpec{{"PCMA", 8000, 1}, {8000, 1, 64000}})); + EXPECT_FALSE(factory->IsSupportedDecoder({"g711", 8000, 1})); + EXPECT_TRUE(factory->IsSupportedDecoder({"PCMU", 8000, 1})); + EXPECT_TRUE(factory->IsSupportedDecoder({"pcma", 8000, 1})); + EXPECT_EQ(nullptr, factory->MakeAudioDecoder({"pcmu", 16000, 1})); + auto dec1 = factory->MakeAudioDecoder({"pcmu", 8000, 1}); + ASSERT_NE(nullptr, dec1); + EXPECT_EQ(8000, dec1->SampleRateHz()); + auto dec2 = factory->MakeAudioDecoder({"PCMA", 8000, 1}); + ASSERT_NE(nullptr, dec2); + EXPECT_EQ(8000, dec2->SampleRateHz()); +} + TEST(AudioDecoderFactoryTemplateTest, G722) { auto factory = CreateAudioDecoderFactory(); EXPECT_THAT(factory->GetSupportedDecoders(), diff --git a/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc b/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc index db477fd00c..58ab28ea41 100644 --- a/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc +++ b/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc @@ -9,6 +9,7 @@ */ #include "webrtc/api/audio_codecs/audio_encoder_factory_template.h" +#include "webrtc/api/audio_codecs/g711/audio_encoder_g711.h" #include "webrtc/api/audio_codecs/g722/audio_encoder_g722.h" #include "webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.h" #include "webrtc/api/audio_codecs/opus/audio_encoder_opus.h" @@ -120,6 +121,25 @@ TEST(AudioEncoderFactoryTemplateTest, TwoEncoderTypes) { EXPECT_EQ(16000, enc2->SampleRateHz()); } +TEST(AudioEncoderFactoryTemplateTest, G711) { + auto factory = CreateAudioEncoderFactory(); + EXPECT_THAT(factory->GetSupportedEncoders(), + testing::ElementsAre( + AudioCodecSpec{{"PCMU", 8000, 1}, {8000, 1, 64000}}, + AudioCodecSpec{{"PCMA", 8000, 1}, {8000, 1, 64000}})); + EXPECT_EQ(rtc::Optional(), + factory->QueryAudioEncoder({"PCMA", 16000, 1})); + EXPECT_EQ(rtc::Optional({8000, 1, 64000}), + factory->QueryAudioEncoder({"PCMA", 8000, 1})); + EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"PCMU", 16000, 1})); + auto enc1 = factory->MakeAudioEncoder(17, {"PCMU", 8000, 1}); + ASSERT_NE(nullptr, enc1); + EXPECT_EQ(8000, enc1->SampleRateHz()); + auto enc2 = factory->MakeAudioEncoder(17, {"PCMA", 8000, 1}); + ASSERT_NE(nullptr, enc2); + EXPECT_EQ(8000, enc2->SampleRateHz()); +} + TEST(AudioEncoderFactoryTemplateTest, G722) { auto factory = CreateAudioEncoderFactory(); EXPECT_THAT(factory->GetSupportedEncoders(),