/* * 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 API_AUDIO_CODECS_AUDIO_ENCODER_FACTORY_TEMPLATE_H_ #define API_AUDIO_CODECS_AUDIO_ENCODER_FACTORY_TEMPLATE_H_ #include #include #include #include #include "absl/base/nullability.h" #include "api/audio_codecs/audio_codec_pair_id.h" #include "api/audio_codecs/audio_encoder.h" #include "api/audio_codecs/audio_encoder_factory.h" #include "api/audio_codecs/audio_format.h" #include "api/environment/environment.h" #include "api/make_ref_counted.h" #include "api/scoped_refptr.h" namespace webrtc { namespace audio_encoder_factory_template_impl { template struct Helper; // Base case: 0 template parameters. template <> struct Helper<> { static void AppendSupportedEncoders(std::vector* specs) {} static std::optional QueryAudioEncoder( const SdpAudioFormat& format) { return std::nullopt; } static absl::Nullable> CreateAudioEncoder( const Environment& env, const SdpAudioFormat& format, const AudioEncoderFactory::Options& options) { return nullptr; } }; // Use ranked overloads (abseil.io/tips/229) for dispatching. struct Rank0 {}; struct Rank1 : Rank0 {}; template (), std::declval(), std::declval())), std::unique_ptr>>> absl::Nullable> CreateEncoder( Rank1, const Environment& env, const typename Trait::Config& config, const AudioEncoderFactory::Options& options) { return Trait::MakeAudioEncoder(env, config, options); } template (), int{}, std::declval>())), std::unique_ptr>>> absl::Nullable> CreateEncoder( Rank0, const Environment& env, const typename Trait::Config& config, const AudioEncoderFactory::Options& options) { return Trait::MakeAudioEncoder(config, options.payload_type, options.codec_pair_id); } // Inductive case: Called with n + 1 template parameters; calls subroutines // with n template parameters. template struct Helper { static void AppendSupportedEncoders(std::vector* specs) { T::AppendSupportedEncoders(specs); Helper::AppendSupportedEncoders(specs); } static std::optional QueryAudioEncoder( const SdpAudioFormat& format) { auto opt_config = T::SdpToConfig(format); static_assert(std::is_same>::value, "T::SdpToConfig() must return a value of type " "std::optional"); return opt_config ? std::optional( T::QueryAudioEncoder(*opt_config)) : Helper::QueryAudioEncoder(format); } static absl::Nullable> CreateAudioEncoder( const Environment& env, const SdpAudioFormat& format, const AudioEncoderFactory::Options& options) { if (auto opt_config = T::SdpToConfig(format); opt_config.has_value()) { return CreateEncoder(Rank1{}, env, *opt_config, options); } return Helper::CreateAudioEncoder(env, format, options); } }; template class AudioEncoderFactoryT : public AudioEncoderFactory { public: std::vector GetSupportedEncoders() override { std::vector specs; Helper::AppendSupportedEncoders(&specs); return specs; } std::optional QueryAudioEncoder( const SdpAudioFormat& format) override { return Helper::QueryAudioEncoder(format); } absl::Nullable> Create( const Environment& env, const SdpAudioFormat& format, Options options) override { return Helper::CreateAudioEncoder(env, format, options); } }; } // namespace audio_encoder_factory_template_impl // Make an AudioEncoderFactory that can create instances of the given encoders. // // Each encoder type is given as a template argument to the function; it should // be a struct with the following static member functions: // // // Converts `audio_format` to a ConfigType instance. Returns an empty // // optional if `audio_format` doesn't correctly specify an encoder of our // // type. // std::optional SdpToConfig(const SdpAudioFormat& audio_format); // // // Appends zero or more AudioCodecSpecs to the list that will be returned // // by AudioEncoderFactory::GetSupportedEncoders(). // void AppendSupportedEncoders(std::vector* specs); // // // Returns information about how this format would be encoded. Used to // // implement AudioEncoderFactory::QueryAudioEncoder(). // AudioCodecInfo QueryAudioEncoder(const ConfigType& config); // // // Creates an AudioEncoder for the specified format. Used to implement // // AudioEncoderFactory::Create. // std::unique_ptr MakeAudioEncoder( // const Environment& env, // const ConfigType& config, // const AudioEncoderFactory::Options& options); // or // std::unique_ptr MakeAudioEncoder( // const ConfigType& config, // int payload_type, // std::optional codec_pair_id); // // ConfigType should be a type that encapsulates all the settings needed to // create an AudioEncoder. T::Config (where T is the encoder struct) should // either be the config type, or an alias for it. // When both MakeAudioEncoder signatures are present, 1st one is preferred. // // Whenever it tries to do something, the new factory will try each of the // encoders in the order they were specified in the template argument list, // stopping at the first one that claims to be able to do the job. // // TODO(kwiberg): Point at CreateBuiltinAudioEncoderFactory() for an example of // how it is used. template rtc::scoped_refptr CreateAudioEncoderFactory() { // There's no technical reason we couldn't allow zero template parameters, // but such a factory couldn't create any encoders, and callers can do this // by mistake by simply forgetting the <> altogether. So we forbid it in // order to prevent caller foot-shooting. static_assert(sizeof...(Ts) >= 1, "Caller must give at least one template parameter"); return rtc::make_ref_counted< audio_encoder_factory_template_impl::AudioEncoderFactoryT>(); } } // namespace webrtc #endif // API_AUDIO_CODECS_AUDIO_ENCODER_FACTORY_TEMPLATE_H_