text: /*
   *  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_DECODER_FACTORY_TEMPLATE_H_
  #define API_AUDIO_CODECS_AUDIO_DECODER_FACTORY_TEMPLATE_H_
  
  #include <memory>
  #include <vector>
  
  #include "api/audio_codecs/audio_decoder_factory.h"
  #include "rtc_base/refcountedobject.h"
  #include "rtc_base/scoped_ref_ptr.h"
  
  namespace webrtc {
  
  namespace audio_decoder_factory_template_impl {
  
  template <typename... Ts>
  struct Helper;
  
  // Base case: 0 template parameters.
  template <>
  struct Helper<> {
    static void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs) {}
    static bool IsSupportedDecoder(const SdpAudioFormat& format) { return false; }
    static std::unique_ptr<AudioDecoder> MakeAudioDecoder(
        const SdpAudioFormat& format,
        absl::optional<AudioCodecPairId> codec_pair_id) {
      return nullptr;
    }
  };
  
  // Inductive case: Called with n + 1 template parameters; calls subroutines
  // with n template parameters.
  template <typename T, typename... Ts>
  struct Helper<T, Ts...> {
    static void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs) {
      T::AppendSupportedDecoders(specs);
      Helper<Ts...>::AppendSupportedDecoders(specs);
    }
    static bool IsSupportedDecoder(const SdpAudioFormat& format) {
      auto opt_config = T::SdpToConfig(format);
      static_assert(std::is_same<decltype(opt_config),
                                 absl::optional<typename T::Config>>::value,
                    "T::SdpToConfig() must return a value of type "
                    "absl::optional<T::Config>");
      return opt_config ? true : Helper<Ts...>::IsSupportedDecoder(format);
    }
    static std::unique_ptr<AudioDecoder> MakeAudioDecoder(
        const SdpAudioFormat& format,
        absl::optional<AudioCodecPairId> codec_pair_id) {
      auto opt_config = T::SdpToConfig(format);
      return opt_config ? T::MakeAudioDecoder(*opt_config, codec_pair_id)
                        : Helper<Ts...>::MakeAudioDecoder(format, codec_pair_id);
    }
  };
  
  template <typename... Ts>
  class AudioDecoderFactoryT : public AudioDecoderFactory {
   public:
    std::vector<AudioCodecSpec> GetSupportedDecoders() override {
      std::vector<AudioCodecSpec> specs;
      Helper<Ts...>::AppendSupportedDecoders(&specs);
      return specs;
    }
  
    bool IsSupportedDecoder(const SdpAudioFormat& format) override {
      return Helper<Ts...>::IsSupportedDecoder(format);
    }
  
    std::unique_ptr<AudioDecoder> MakeAudioDecoder(
        const SdpAudioFormat& format,
        absl::optional<AudioCodecPairId> codec_pair_id) override {
      return Helper<Ts...>::MakeAudioDecoder(format, codec_pair_id);
    }
  };
  
  }  // namespace audio_decoder_factory_template_impl
  
  // Make an AudioDecoderFactory that can create instances of the given decoders.
  //
  // Each decoder 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 decoder of our
  //   // type.
  //   absl::optional<ConfigType> SdpToConfig(const SdpAudioFormat& audio_format);
  //
  //   // Appends zero or more AudioCodecSpecs to the list that will be returned
  //   // by AudioDecoderFactory::GetSupportedDecoders().
  //   void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs);
  //
  //   // Creates an AudioDecoder for the specified format. Used to implement
  //   // AudioDecoderFactory::MakeAudioDecoder().
  //   std::unique_ptr<AudioDecoder> MakeAudioDecoder(
  //       const ConfigType& config,
  //       absl::optional<AudioCodecPairId> codec_pair_id);
  //
  // ConfigType should be a type that encapsulates all the settings needed to
  // create an AudioDecoder. T::Config (where T is the decoder struct) should
  // either be the config type, or an alias for it.
  //
  // Whenever it tries to do something, the new factory will try each of the
  // decoder types 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.
  //
  // NOTE: This function is still under development and may change without notice.
  //
  // TODO(kwiberg): Point at CreateBuiltinAudioDecoderFactory() for an example of
  // how it is used.
  template <typename... Ts>
  rtc::scoped_refptr<AudioDecoderFactory> CreateAudioDecoderFactory() {
    // There's no technical reason we couldn't allow zero template parameters,
    // but such a factory couldn't create any decoders, 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::scoped_refptr<AudioDecoderFactory>(
        new rtc::RefCountedObject<
            audio_decoder_factory_template_impl::AudioDecoderFactoryT<Ts...>>());
  }
  
  }  // namespace webrtc
  
  #endif  // API_AUDIO_CODECS_AUDIO_DECODER_FACTORY_TEMPLATE_H_
  