Move FunctionView from AudioCodingModule to the rtc namespace
It's a very general type, and we're about to start needing it in other places besides AudioCodingModule. BUG=webrtc:5801 Review-Url: https://codereview.webrtc.org/2380463003 Cr-Commit-Position: refs/heads/master@{#14423}
This commit is contained in:
@ -383,6 +383,7 @@ if (rtc_include_tests) {
|
|||||||
"base/file_unittest.cc",
|
"base/file_unittest.cc",
|
||||||
"base/filerotatingstream_unittest.cc",
|
"base/filerotatingstream_unittest.cc",
|
||||||
"base/fileutils_unittest.cc",
|
"base/fileutils_unittest.cc",
|
||||||
|
"base/function_view_unittest.cc",
|
||||||
"base/helpers_unittest.cc",
|
"base/helpers_unittest.cc",
|
||||||
"base/httpbase_unittest.cc",
|
"base/httpbase_unittest.cc",
|
||||||
"base/httpcommon_unittest.cc",
|
"base/httpcommon_unittest.cc",
|
||||||
|
|||||||
@ -116,6 +116,7 @@ rtc_static_library("rtc_base_approved") {
|
|||||||
"file.cc",
|
"file.cc",
|
||||||
"file.h",
|
"file.h",
|
||||||
"format_macros.h",
|
"format_macros.h",
|
||||||
|
"function_view.h",
|
||||||
"location.cc",
|
"location.cc",
|
||||||
"location.h",
|
"location.h",
|
||||||
"md5.cc",
|
"md5.cc",
|
||||||
|
|||||||
@ -58,6 +58,7 @@
|
|||||||
'file.cc',
|
'file.cc',
|
||||||
'file.h',
|
'file.h',
|
||||||
'format_macros.h',
|
'format_macros.h',
|
||||||
|
'function_view.h',
|
||||||
'location.h',
|
'location.h',
|
||||||
'location.cc',
|
'location.cc',
|
||||||
'md5.cc',
|
'md5.cc',
|
||||||
|
|||||||
70
webrtc/base/function_view.h
Normal file
70
webrtc/base/function_view.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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_BASE_FUNCTION_VIEW_H_
|
||||||
|
#define WEBRTC_BASE_FUNCTION_VIEW_H_
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
// Just like std::function, FunctionView will wrap any callable and hide its
|
||||||
|
// actual type, exposing only its signature. But unlike std::function,
|
||||||
|
// FunctionView doesn't own its callable---it just points to it. Thus, it's a
|
||||||
|
// good choice mainly as a function argument when the callable argument will
|
||||||
|
// not be called again once the function has returned.
|
||||||
|
//
|
||||||
|
// TODO(kwiberg): FunctionView doesn't work with function pointers, just with
|
||||||
|
// lambdas. It's trivial to work around this by wrapping the function pointer
|
||||||
|
// in a stateless lambda, but it's tedious so it'd be nice to not have to do
|
||||||
|
// it.
|
||||||
|
|
||||||
|
namespace rtc {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class FunctionView; // Undefined.
|
||||||
|
|
||||||
|
template <typename RetT, typename... ArgT>
|
||||||
|
class FunctionView<RetT(ArgT...)> final {
|
||||||
|
public:
|
||||||
|
// This constructor is implicit, so that callers won't have to convert
|
||||||
|
// lambdas and other callables to FunctionView<Blah(Blah, Blah)> explicitly.
|
||||||
|
// This is safe because FunctionView is only a reference to the real
|
||||||
|
// callable.
|
||||||
|
//
|
||||||
|
// We jump through some template metaprogramming hoops to ensure that this
|
||||||
|
// constructor does *not* accept FunctionView arguments. That way, copy
|
||||||
|
// construction, assignment, swap etc. will all do the obvious thing (because
|
||||||
|
// they use the implicitly-declared copy constructor and copy assignment),
|
||||||
|
// and we will never get a FunctionView object that points to another
|
||||||
|
// FunctionView.
|
||||||
|
template <typename F,
|
||||||
|
typename std::enable_if<!std::is_same<
|
||||||
|
FunctionView,
|
||||||
|
typename std::remove_cv<typename std::remove_reference<
|
||||||
|
F>::type>::type>::value>::type* = nullptr>
|
||||||
|
FunctionView(F&& f)
|
||||||
|
: f_(&f), call_(Call<typename std::remove_reference<F>::type>) {}
|
||||||
|
|
||||||
|
RetT operator()(ArgT... args) const {
|
||||||
|
return call_(f_, std::forward<ArgT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename F>
|
||||||
|
static RetT Call(void* f, ArgT... args) {
|
||||||
|
return (*static_cast<F*>(f))(std::forward<ArgT>(args)...);
|
||||||
|
}
|
||||||
|
void* f_;
|
||||||
|
RetT (*call_)(void* f, ArgT... args);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace rtc
|
||||||
|
|
||||||
|
#endif // WEBRTC_BASE_FUNCTION_VIEW_H_
|
||||||
146
webrtc/base/function_view_unittest.cc
Normal file
146
webrtc/base/function_view_unittest.cc
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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 <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "webrtc/base/function_view.h"
|
||||||
|
#include "webrtc/base/gunit.h"
|
||||||
|
|
||||||
|
namespace rtc {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
int CallWith33(rtc::FunctionView<int(int)> fv) {
|
||||||
|
return fv(33);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// Test the main use case of FunctionView: implicitly converting a lambda
|
||||||
|
// function argument.
|
||||||
|
TEST(FunctionViewTest, ImplicitConversion) {
|
||||||
|
EXPECT_EQ(38, CallWith33([](int x) { return x + 5; }));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FunctionViewTest, IntIntLambdaWithoutState) {
|
||||||
|
auto f = [](int x) { return x + 1; };
|
||||||
|
EXPECT_EQ(18, f(17));
|
||||||
|
rtc::FunctionView<int(int)> fv(f);
|
||||||
|
EXPECT_EQ(18, fv(17));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FunctionViewTest, IntVoidLambdaWithState) {
|
||||||
|
int x = 13;
|
||||||
|
auto f = [x]() mutable { return ++x; };
|
||||||
|
rtc::FunctionView<int()> fv(f);
|
||||||
|
EXPECT_EQ(14, f());
|
||||||
|
EXPECT_EQ(15, fv());
|
||||||
|
EXPECT_EQ(16, f());
|
||||||
|
EXPECT_EQ(17, fv());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that FunctionView handles move-only arguments and return values.
|
||||||
|
TEST(FunctionViewTest, UniquePtrPassthrough) {
|
||||||
|
auto f = [](std::unique_ptr<int> x) { return x; };
|
||||||
|
rtc::FunctionView<std::unique_ptr<int>(std::unique_ptr<int>)> fv(f);
|
||||||
|
std::unique_ptr<int> x(new int);
|
||||||
|
int* x_addr = x.get();
|
||||||
|
auto y = fv(std::move(x));
|
||||||
|
EXPECT_EQ(x_addr, y.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FunctionViewTest, CopyConstructor) {
|
||||||
|
auto f17 = [] { return 17; };
|
||||||
|
rtc::FunctionView<int()> fv1(f17);
|
||||||
|
rtc::FunctionView<int()> fv2(fv1);
|
||||||
|
EXPECT_EQ(17, fv1());
|
||||||
|
EXPECT_EQ(17, fv2());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FunctionViewTest, MoveConstructorIsCopy) {
|
||||||
|
auto f17 = [] { return 17; };
|
||||||
|
rtc::FunctionView<int()> fv1(f17);
|
||||||
|
rtc::FunctionView<int()> fv2(std::move(fv1));
|
||||||
|
EXPECT_EQ(17, fv1());
|
||||||
|
EXPECT_EQ(17, fv2());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FunctionViewTest, CopyAssignment) {
|
||||||
|
auto f17 = [] { return 17; };
|
||||||
|
rtc::FunctionView<int()> fv1(f17);
|
||||||
|
auto f23 = [] { return 23; };
|
||||||
|
rtc::FunctionView<int()> fv2(f23);
|
||||||
|
EXPECT_EQ(17, fv1());
|
||||||
|
EXPECT_EQ(23, fv2());
|
||||||
|
fv2 = fv1;
|
||||||
|
EXPECT_EQ(17, fv1());
|
||||||
|
EXPECT_EQ(17, fv2());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FunctionViewTest, MoveAssignmentIsCopy) {
|
||||||
|
auto f17 = [] { return 17; };
|
||||||
|
rtc::FunctionView<int()> fv1(f17);
|
||||||
|
auto f23 = [] { return 23; };
|
||||||
|
rtc::FunctionView<int()> fv2(f23);
|
||||||
|
EXPECT_EQ(17, fv1());
|
||||||
|
EXPECT_EQ(23, fv2());
|
||||||
|
fv2 = std::move(fv1);
|
||||||
|
EXPECT_EQ(17, fv1());
|
||||||
|
EXPECT_EQ(17, fv2());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FunctionViewTest, Swap) {
|
||||||
|
auto f17 = [] { return 17; };
|
||||||
|
rtc::FunctionView<int()> fv1(f17);
|
||||||
|
auto f23 = [] { return 23; };
|
||||||
|
rtc::FunctionView<int()> fv2(f23);
|
||||||
|
EXPECT_EQ(17, fv1());
|
||||||
|
EXPECT_EQ(23, fv2());
|
||||||
|
using std::swap;
|
||||||
|
swap(fv1, fv2);
|
||||||
|
EXPECT_EQ(23, fv1());
|
||||||
|
EXPECT_EQ(17, fv2());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that when you copy-construct a FunctionView, the new object points to
|
||||||
|
// the same function as the old one, as opposed to the new object pointing to
|
||||||
|
// the old one.
|
||||||
|
TEST(FunctionViewTest, CopyConstructorChaining) {
|
||||||
|
auto f17 = [] { return 17; };
|
||||||
|
rtc::FunctionView<int()> fv1(f17);
|
||||||
|
rtc::FunctionView<int()> fv2(fv1);
|
||||||
|
EXPECT_EQ(17, fv1());
|
||||||
|
EXPECT_EQ(17, fv2());
|
||||||
|
auto f23 = [] { return 23; };
|
||||||
|
fv1 = f23;
|
||||||
|
EXPECT_EQ(23, fv1());
|
||||||
|
EXPECT_EQ(17, fv2());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that when you assign one FunctionView to another, we actually make a
|
||||||
|
// copy as opposed to making the second FunctionView point to the first one.
|
||||||
|
TEST(FunctionViewTest, CopyAssignmentChaining) {
|
||||||
|
auto f17 = [] { return 17; };
|
||||||
|
rtc::FunctionView<int()> fv1(f17);
|
||||||
|
auto f3 = [] { return 3; };
|
||||||
|
rtc::FunctionView<int()> fv2(f3);
|
||||||
|
EXPECT_EQ(17, fv1());
|
||||||
|
EXPECT_EQ(3, fv2());
|
||||||
|
fv2 = fv1;
|
||||||
|
EXPECT_EQ(17, fv1());
|
||||||
|
EXPECT_EQ(17, fv2());
|
||||||
|
auto f23 = [] { return 23; };
|
||||||
|
fv1 = f23;
|
||||||
|
EXPECT_EQ(23, fv1());
|
||||||
|
EXPECT_EQ(17, fv2());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace rtc
|
||||||
@ -45,10 +45,11 @@ class AudioCodingModuleImpl final : public AudioCodingModule {
|
|||||||
void RegisterExternalSendCodec(
|
void RegisterExternalSendCodec(
|
||||||
AudioEncoder* external_speech_encoder) override;
|
AudioEncoder* external_speech_encoder) override;
|
||||||
|
|
||||||
void ModifyEncoder(
|
void ModifyEncoder(rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)>
|
||||||
FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier) override;
|
modifier) override;
|
||||||
|
|
||||||
void QueryEncoder(FunctionView<void(const AudioEncoder*)> query) override;
|
void QueryEncoder(
|
||||||
|
rtc::FunctionView<void(const AudioEncoder*)> query) override;
|
||||||
|
|
||||||
// Get current send codec.
|
// Get current send codec.
|
||||||
rtc::Optional<CodecInst> SendCodec() const override;
|
rtc::Optional<CodecInst> SendCodec() const override;
|
||||||
@ -123,7 +124,7 @@ class AudioCodingModuleImpl final : public AudioCodingModule {
|
|||||||
int RegisterReceiveCodec(const CodecInst& receive_codec) override;
|
int RegisterReceiveCodec(const CodecInst& receive_codec) override;
|
||||||
int RegisterReceiveCodec(
|
int RegisterReceiveCodec(
|
||||||
const CodecInst& receive_codec,
|
const CodecInst& receive_codec,
|
||||||
FunctionView<std::unique_ptr<AudioDecoder>()> isac_factory) override;
|
rtc::FunctionView<std::unique_ptr<AudioDecoder>()> isac_factory) override;
|
||||||
|
|
||||||
int RegisterExternalReceiveCodec(int rtp_payload_type,
|
int RegisterExternalReceiveCodec(int rtp_payload_type,
|
||||||
AudioDecoder* external_decoder,
|
AudioDecoder* external_decoder,
|
||||||
@ -223,7 +224,7 @@ class AudioCodingModuleImpl final : public AudioCodingModule {
|
|||||||
|
|
||||||
int RegisterReceiveCodecUnlocked(
|
int RegisterReceiveCodecUnlocked(
|
||||||
const CodecInst& codec,
|
const CodecInst& codec,
|
||||||
FunctionView<std::unique_ptr<AudioDecoder>()> isac_factory)
|
rtc::FunctionView<std::unique_ptr<AudioDecoder>()> isac_factory)
|
||||||
EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_);
|
EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_);
|
||||||
|
|
||||||
int Add10MsDataInternal(const AudioFrame& audio_frame, InputData* input_data)
|
int Add10MsDataInternal(const AudioFrame& audio_frame, InputData* input_data)
|
||||||
@ -587,7 +588,7 @@ void AudioCodingModuleImpl::RegisterExternalSendCodec(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioCodingModuleImpl::ModifyEncoder(
|
void AudioCodingModuleImpl::ModifyEncoder(
|
||||||
FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier) {
|
rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier) {
|
||||||
rtc::CritScope lock(&acm_crit_sect_);
|
rtc::CritScope lock(&acm_crit_sect_);
|
||||||
|
|
||||||
// Wipe the encoder factory, so that everything that relies on it will fail.
|
// Wipe the encoder factory, so that everything that relies on it will fail.
|
||||||
@ -601,7 +602,7 @@ void AudioCodingModuleImpl::ModifyEncoder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioCodingModuleImpl::QueryEncoder(
|
void AudioCodingModuleImpl::QueryEncoder(
|
||||||
FunctionView<void(const AudioEncoder*)> query) {
|
rtc::FunctionView<void(const AudioEncoder*)> query) {
|
||||||
rtc::CritScope lock(&acm_crit_sect_);
|
rtc::CritScope lock(&acm_crit_sect_);
|
||||||
query(encoder_stack_.get());
|
query(encoder_stack_.get());
|
||||||
}
|
}
|
||||||
@ -995,14 +996,14 @@ int AudioCodingModuleImpl::RegisterReceiveCodec(const CodecInst& codec) {
|
|||||||
|
|
||||||
int AudioCodingModuleImpl::RegisterReceiveCodec(
|
int AudioCodingModuleImpl::RegisterReceiveCodec(
|
||||||
const CodecInst& codec,
|
const CodecInst& codec,
|
||||||
FunctionView<std::unique_ptr<AudioDecoder>()> isac_factory) {
|
rtc::FunctionView<std::unique_ptr<AudioDecoder>()> isac_factory) {
|
||||||
rtc::CritScope lock(&acm_crit_sect_);
|
rtc::CritScope lock(&acm_crit_sect_);
|
||||||
return RegisterReceiveCodecUnlocked(codec, isac_factory);
|
return RegisterReceiveCodecUnlocked(codec, isac_factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
int AudioCodingModuleImpl::RegisterReceiveCodecUnlocked(
|
int AudioCodingModuleImpl::RegisterReceiveCodecUnlocked(
|
||||||
const CodecInst& codec,
|
const CodecInst& codec,
|
||||||
FunctionView<std::unique_ptr<AudioDecoder>()> isac_factory) {
|
rtc::FunctionView<std::unique_ptr<AudioDecoder>()> isac_factory) {
|
||||||
RTC_DCHECK(receiver_initialized_);
|
RTC_DCHECK(receiver_initialized_);
|
||||||
if (codec.channels > 2) {
|
if (codec.channels > 2) {
|
||||||
LOG_F(LS_ERROR) << "Unsupported number of channels: " << codec.channels;
|
LOG_F(LS_ERROR) << "Unsupported number of channels: " << codec.channels;
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "webrtc/base/deprecation.h"
|
#include "webrtc/base/deprecation.h"
|
||||||
|
#include "webrtc/base/function_view.h"
|
||||||
#include "webrtc/base/optional.h"
|
#include "webrtc/base/optional.h"
|
||||||
#include "webrtc/common_types.h"
|
#include "webrtc/common_types.h"
|
||||||
#include "webrtc/modules/audio_coding/codecs/audio_decoder_factory.h"
|
#include "webrtc/modules/audio_coding/codecs/audio_decoder_factory.h"
|
||||||
@ -209,48 +210,18 @@ class AudioCodingModule {
|
|||||||
virtual void RegisterExternalSendCodec(
|
virtual void RegisterExternalSendCodec(
|
||||||
AudioEncoder* external_speech_encoder) = 0;
|
AudioEncoder* external_speech_encoder) = 0;
|
||||||
|
|
||||||
// Just like std::function, FunctionView will wrap any callable and hide its
|
|
||||||
// actual type, exposing only its signature. But unlike std::function,
|
|
||||||
// FunctionView doesn't own its callable---it just points to it. Thus, it's a
|
|
||||||
// good choice mainly as a function argument when the callable argument will
|
|
||||||
// not be called again once the function has returned.
|
|
||||||
template <typename T>
|
|
||||||
class FunctionView; // Undefined.
|
|
||||||
|
|
||||||
template <typename RetT, typename... ArgT>
|
|
||||||
class FunctionView<RetT(ArgT...)> final {
|
|
||||||
public:
|
|
||||||
// This constructor is implicit, so that callers won't have to convert
|
|
||||||
// lambdas to FunctionView<Blah(Blah, Blah)> explicitly. This is safe
|
|
||||||
// because FunctionView is only a reference to the real callable.
|
|
||||||
template <typename F>
|
|
||||||
FunctionView(F&& f)
|
|
||||||
: f_(&f), call_(Call<typename std::remove_reference<F>::type>) {}
|
|
||||||
|
|
||||||
RetT operator()(ArgT... args) const {
|
|
||||||
return call_(f_, std::forward<ArgT>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
template <typename F>
|
|
||||||
static RetT Call(void* f, ArgT... args) {
|
|
||||||
return (*static_cast<F*>(f))(std::forward<ArgT>(args)...);
|
|
||||||
}
|
|
||||||
void* f_;
|
|
||||||
RetT (*call_)(void* f, ArgT... args);
|
|
||||||
};
|
|
||||||
|
|
||||||
// |modifier| is called exactly once with one argument: a pointer to the
|
// |modifier| is called exactly once with one argument: a pointer to the
|
||||||
// unique_ptr that holds the current encoder (which is null if there is no
|
// unique_ptr that holds the current encoder (which is null if there is no
|
||||||
// current encoder). For the duration of the call, |modifier| has exclusive
|
// current encoder). For the duration of the call, |modifier| has exclusive
|
||||||
// access to the unique_ptr; it may call the encoder, steal the encoder and
|
// access to the unique_ptr; it may call the encoder, steal the encoder and
|
||||||
// replace it with another encoder or with nullptr, etc.
|
// replace it with another encoder or with nullptr, etc.
|
||||||
virtual void ModifyEncoder(
|
virtual void ModifyEncoder(
|
||||||
FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier) = 0;
|
rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier) = 0;
|
||||||
|
|
||||||
// |modifier| is called exactly once with one argument: a const pointer to the
|
// |modifier| is called exactly once with one argument: a const pointer to the
|
||||||
// current encoder (which is null if there is no current encoder).
|
// current encoder (which is null if there is no current encoder).
|
||||||
virtual void QueryEncoder(FunctionView<void(AudioEncoder const*)> query) = 0;
|
virtual void QueryEncoder(
|
||||||
|
rtc::FunctionView<void(AudioEncoder const*)> query) = 0;
|
||||||
|
|
||||||
// Utility method for simply replacing the existing encoder with a new one.
|
// Utility method for simply replacing the existing encoder with a new one.
|
||||||
void SetEncoder(std::unique_ptr<AudioEncoder> new_encoder) {
|
void SetEncoder(std::unique_ptr<AudioEncoder> new_encoder) {
|
||||||
@ -529,7 +500,7 @@ class AudioCodingModule {
|
|||||||
// the decoder being registered is iSAC.
|
// the decoder being registered is iSAC.
|
||||||
virtual int RegisterReceiveCodec(
|
virtual int RegisterReceiveCodec(
|
||||||
const CodecInst& receive_codec,
|
const CodecInst& receive_codec,
|
||||||
FunctionView<std::unique_ptr<AudioDecoder>()> isac_factory) = 0;
|
rtc::FunctionView<std::unique_ptr<AudioDecoder>()> isac_factory) = 0;
|
||||||
|
|
||||||
// Registers an external decoder. The name is only used to provide information
|
// Registers an external decoder. The name is only used to provide information
|
||||||
// back to the caller about the decoder. Hence, the name is arbitrary, and may
|
// back to the caller about the decoder. Hence, the name is arbitrary, and may
|
||||||
|
|||||||
Reference in New Issue
Block a user