audio_decoder_factory_template.h (7094B)
1 /* 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef API_AUDIO_CODECS_AUDIO_DECODER_FACTORY_TEMPLATE_H_ 12 #define API_AUDIO_CODECS_AUDIO_DECODER_FACTORY_TEMPLATE_H_ 13 14 #include <memory> 15 #include <optional> 16 #include <type_traits> 17 #include <utility> 18 #include <vector> 19 20 #include "absl/base/nullability.h" 21 #include "api/audio_codecs/audio_codec_pair_id.h" 22 #include "api/audio_codecs/audio_decoder.h" 23 #include "api/audio_codecs/audio_decoder_factory.h" 24 #include "api/audio_codecs/audio_format.h" 25 #include "api/environment/environment.h" 26 #include "api/make_ref_counted.h" 27 #include "api/scoped_refptr.h" 28 29 namespace webrtc { 30 31 namespace audio_decoder_factory_template_impl { 32 33 template <typename... Ts> 34 struct Helper; 35 36 // Base case: 0 template parameters. 37 template <> 38 struct Helper<> { 39 static void AppendSupportedDecoders( 40 std::vector<AudioCodecSpec>* /* specs */) {} 41 static bool IsSupportedDecoder(const SdpAudioFormat& /* format */) { 42 return false; 43 } 44 45 static absl_nullable std::unique_ptr<AudioDecoder> MakeAudioDecoder( 46 const Environment& /* env */, 47 const SdpAudioFormat& /* format */, 48 std::optional<AudioCodecPairId> /* codec_pair_id */) { 49 return nullptr; 50 } 51 }; 52 53 // Use ranked overloads (abseil.io/tips/229) for dispatching. 54 struct Rank0 {}; 55 struct Rank1 : Rank0 {}; 56 57 template <typename Trait, 58 typename = std::enable_if_t<std::is_convertible_v< 59 decltype(Trait::MakeAudioDecoder( 60 std::declval<Environment>(), 61 std::declval<typename Trait::Config>(), 62 std::declval<std::optional<AudioCodecPairId>>())), 63 std::unique_ptr<AudioDecoder>>>> 64 absl_nullable std::unique_ptr<AudioDecoder> CreateDecoder( 65 Rank1, 66 const Environment& env, 67 const typename Trait::Config& config, 68 std::optional<AudioCodecPairId> codec_pair_id) { 69 return Trait::MakeAudioDecoder(env, config, codec_pair_id); 70 } 71 72 template <typename Trait, 73 typename = std::enable_if_t<std::is_convertible_v< 74 decltype(Trait::MakeAudioDecoder( 75 std::declval<typename Trait::Config>(), 76 std::declval<std::optional<AudioCodecPairId>>())), 77 std::unique_ptr<AudioDecoder>>>> 78 absl_nullable std::unique_ptr<AudioDecoder> CreateDecoder( 79 Rank0, 80 const Environment& /* env */, 81 const typename Trait::Config& config, 82 std::optional<AudioCodecPairId> codec_pair_id) { 83 return Trait::MakeAudioDecoder(config, codec_pair_id); 84 } 85 86 // Inductive case: Called with n + 1 template parameters; calls subroutines 87 // with n template parameters. 88 template <typename T, typename... Ts> 89 struct Helper<T, Ts...> { 90 static void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs) { 91 T::AppendSupportedDecoders(specs); 92 Helper<Ts...>::AppendSupportedDecoders(specs); 93 } 94 static bool IsSupportedDecoder(const SdpAudioFormat& format) { 95 auto opt_config = T::SdpToConfig(format); 96 static_assert(std::is_same<decltype(opt_config), 97 std::optional<typename T::Config>>::value, 98 "T::SdpToConfig() must return a value of type " 99 "std::optional<T::Config>"); 100 return opt_config ? true : Helper<Ts...>::IsSupportedDecoder(format); 101 } 102 103 static absl_nullable std::unique_ptr<AudioDecoder> MakeAudioDecoder( 104 const Environment& env, 105 const SdpAudioFormat& format, 106 std::optional<AudioCodecPairId> codec_pair_id) { 107 auto opt_config = T::SdpToConfig(format); 108 return opt_config.has_value() 109 ? CreateDecoder<T>(Rank1{}, env, *opt_config, codec_pair_id) 110 : Helper<Ts...>::MakeAudioDecoder(env, format, codec_pair_id); 111 } 112 }; 113 114 template <typename... Ts> 115 class AudioDecoderFactoryT : public AudioDecoderFactory { 116 public: 117 std::vector<AudioCodecSpec> GetSupportedDecoders() override { 118 std::vector<AudioCodecSpec> specs; 119 Helper<Ts...>::AppendSupportedDecoders(&specs); 120 return specs; 121 } 122 123 bool IsSupportedDecoder(const SdpAudioFormat& format) override { 124 return Helper<Ts...>::IsSupportedDecoder(format); 125 } 126 127 absl_nullable std::unique_ptr<AudioDecoder> Create( 128 const Environment& env, 129 const SdpAudioFormat& format, 130 std::optional<AudioCodecPairId> codec_pair_id) override { 131 return Helper<Ts...>::MakeAudioDecoder(env, format, codec_pair_id); 132 } 133 }; 134 135 } // namespace audio_decoder_factory_template_impl 136 137 // Make an AudioDecoderFactory that can create instances of the given decoders. 138 // 139 // Each decoder type is given as a template argument to the function; it should 140 // be a struct with the following static member functions: 141 // 142 // // Converts `audio_format` to a ConfigType instance. Returns an empty 143 // // optional if `audio_format` doesn't correctly specify a decoder of our 144 // // type. 145 // std::optional<ConfigType> SdpToConfig(const SdpAudioFormat& audio_format); 146 // 147 // // Appends zero or more AudioCodecSpecs to the list that will be returned 148 // // by AudioDecoderFactory::GetSupportedDecoders(). 149 // void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs); 150 // 151 // // Creates an AudioDecoder for the specified format. Used to implement 152 // // AudioDecoderFactory::Create(). 153 // std::unique_ptr<AudioEncoder> MakeAudioDecoder( 154 // const Environment& env, 155 // const ConfigType& config, 156 // std::optional<AudioCodecPairId> codec_pair_id); 157 // or 158 // std::unique_ptr<AudioDecoder> MakeAudioDecoder( 159 // const ConfigType& config, 160 // std::optional<AudioCodecPairId> codec_pair_id); 161 // 162 // ConfigType should be a type that encapsulates all the settings needed to 163 // create an AudioDecoder. T::Config (where T is the decoder struct) should 164 // either be the config type, or an alias for it. 165 // 166 // Whenever it tries to do something, the new factory will try each of the 167 // decoder types in the order they were specified in the template argument 168 // list, stopping at the first one that claims to be able to do the job. 169 // 170 // TODO(kwiberg): Point at CreateBuiltinAudioDecoderFactory() for an example of 171 // how it is used. 172 template <typename... Ts> 173 scoped_refptr<AudioDecoderFactory> CreateAudioDecoderFactory() { 174 // There's no technical reason we couldn't allow zero template parameters, 175 // but such a factory couldn't create any decoders, and callers can do this 176 // by mistake by simply forgetting the <> altogether. So we forbid it in 177 // order to prevent caller foot-shooting. 178 static_assert(sizeof...(Ts) >= 1, 179 "Caller must give at least one template parameter"); 180 181 return make_ref_counted< 182 audio_decoder_factory_template_impl::AudioDecoderFactoryT<Ts...>>(); 183 } 184 185 } // namespace webrtc 186 187 #endif // API_AUDIO_CODECS_AUDIO_DECODER_FACTORY_TEMPLATE_H_